toolception 0.1.0 → 0.2.1
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 +131 -7
- package/dist/index.js +233 -187
- package/dist/index.js.map +1 -1
- package/package.json +11 -2
package/README.md
CHANGED
|
@@ -75,14 +75,25 @@ const configSchema = {
|
|
|
75
75
|
} as const;
|
|
76
76
|
```
|
|
77
77
|
|
|
78
|
-
### Step 7: Create
|
|
78
|
+
### Step 7: Create the MCP SDK server and start Toolception
|
|
79
79
|
|
|
80
80
|
```ts
|
|
81
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
82
|
+
|
|
83
|
+
// You own the SDK server; pass a factory into Toolception (required in DYNAMIC mode)
|
|
84
|
+
const createServer = () =>
|
|
85
|
+
new McpServer({
|
|
86
|
+
name: "my-mcp-server",
|
|
87
|
+
version: "0.0.0",
|
|
88
|
+
capabilities: { tools: { listChanged: true } },
|
|
89
|
+
});
|
|
90
|
+
|
|
81
91
|
const { start, close } = await createMcpServer({
|
|
82
92
|
catalog,
|
|
83
93
|
moduleLoaders,
|
|
84
94
|
startup: { mode: "DYNAMIC" },
|
|
85
95
|
http: { port: 3000 },
|
|
96
|
+
createServer,
|
|
86
97
|
// configSchema, // uncomment to expose at /.well-known/mcp-config
|
|
87
98
|
});
|
|
88
99
|
await start();
|
|
@@ -103,9 +114,11 @@ process.on("SIGTERM", async () => {
|
|
|
103
114
|
|
|
104
115
|
## Static startup
|
|
105
116
|
|
|
106
|
-
Enable some or ALL toolsets at bootstrap:
|
|
117
|
+
Enable some or ALL toolsets at bootstrap. Note: provide a server or factory:
|
|
107
118
|
|
|
108
119
|
```ts
|
|
120
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
121
|
+
|
|
109
122
|
const staticCatalog = {
|
|
110
123
|
search: { name: "Search", description: "Search tools", modules: ["search"] },
|
|
111
124
|
quotes: { name: "Quotes", description: "Market quotes", modules: ["quotes"] },
|
|
@@ -115,12 +128,22 @@ createMcpServer({
|
|
|
115
128
|
catalog: staticCatalog,
|
|
116
129
|
startup: { mode: "STATIC", toolsets: ["search", "quotes"] },
|
|
117
130
|
http: { port: 3001 },
|
|
131
|
+
server: new McpServer({
|
|
132
|
+
name: "static-1",
|
|
133
|
+
version: "0.0.0",
|
|
134
|
+
capabilities: { tools: { listChanged: false } },
|
|
135
|
+
}),
|
|
118
136
|
});
|
|
119
137
|
|
|
120
138
|
createMcpServer({
|
|
121
139
|
catalog: staticCatalog,
|
|
122
140
|
startup: { mode: "STATIC", toolsets: "ALL" },
|
|
123
141
|
http: { port: 3002 },
|
|
142
|
+
server: new McpServer({
|
|
143
|
+
name: "static-2",
|
|
144
|
+
version: "0.0.0",
|
|
145
|
+
capabilities: { tools: { listChanged: false } },
|
|
146
|
+
}),
|
|
124
147
|
});
|
|
125
148
|
```
|
|
126
149
|
|
|
@@ -128,7 +151,13 @@ createMcpServer({
|
|
|
128
151
|
|
|
129
152
|
### createMcpServer(options)
|
|
130
153
|
|
|
131
|
-
|
|
154
|
+
Wires your MCP SDK server to dynamic/static tool management and a Fastify HTTP transport.
|
|
155
|
+
|
|
156
|
+
Requirements
|
|
157
|
+
|
|
158
|
+
- `createServer` must be provided.
|
|
159
|
+
- In DYNAMIC mode, a fresh server instance is created per client via `createServer`.
|
|
160
|
+
- In STATIC mode, a single server instance is created once via `createServer` and reused for all clients.
|
|
132
161
|
|
|
133
162
|
#### options.catalog (required)
|
|
134
163
|
|
|
@@ -142,12 +171,59 @@ Creates an MCP server with dynamic/static tool management and Fastify HTTP trans
|
|
|
142
171
|
|
|
143
172
|
- Maps module keys to async loaders returning `McpToolDefinition[]`. Referenced by toolsets via `modules: [key]`.
|
|
144
173
|
|
|
174
|
+
Usage and behavior
|
|
175
|
+
|
|
176
|
+
| Aspect | Details |
|
|
177
|
+
| ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
178
|
+
| Key naming | The object key is the module identifier referenced in `catalog[toolset].modules`. Example: `{ ext: async () => [...] }` and `modules: ["ext"]`. |
|
|
179
|
+
| Loader signature | `(context?: unknown) => Promise<McpToolDefinition[]>` or `McpToolDefinition[]` |
|
|
180
|
+
| When called | STATIC mode: at startup (for specified toolsets or ALL). DYNAMIC mode: when a toolset is enabled via meta-tools. |
|
|
181
|
+
| Return value | An array of tools to register. Tool names should be unique per toolset; if `namespaceToolsWithSetKey` is true, names are prefixed at registration. |
|
|
182
|
+
| Errors | Throwing rejects the enable/preload flow for that toolset and surfaces an error to the caller. |
|
|
183
|
+
| Idempotency | Loaders may be invoked multiple times across runs/clients. Keep them deterministic/idempotent. Implement internal caching if they perform expensive I/O. |
|
|
184
|
+
|
|
185
|
+
Example
|
|
186
|
+
|
|
187
|
+
```ts
|
|
188
|
+
const moduleLoaders = {
|
|
189
|
+
ext: async (ctx?: unknown) => [
|
|
190
|
+
{
|
|
191
|
+
name: "echo",
|
|
192
|
+
description: "Echo back provided text",
|
|
193
|
+
inputSchema: {
|
|
194
|
+
type: "object",
|
|
195
|
+
properties: { text: { type: "string" } },
|
|
196
|
+
required: ["text"],
|
|
197
|
+
},
|
|
198
|
+
handler: async ({ text }: { text: string }) => ({
|
|
199
|
+
content: [{ type: "text", text }],
|
|
200
|
+
}),
|
|
201
|
+
},
|
|
202
|
+
],
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
const catalog = {
|
|
206
|
+
ext: { name: "Extensions", description: "Extra tools", modules: ["ext"] },
|
|
207
|
+
};
|
|
208
|
+
```
|
|
209
|
+
|
|
145
210
|
#### options.startup (optional)
|
|
146
211
|
|
|
147
212
|
`{ mode?: "DYNAMIC" | "STATIC"; toolsets?: string[] | "ALL" }`
|
|
148
213
|
|
|
149
214
|
- Controls startup behavior. In STATIC mode, pre-load specific toolsets (or ALL). In DYNAMIC, register meta-tools and load on demand.
|
|
150
215
|
|
|
216
|
+
Startup precedence and validation
|
|
217
|
+
|
|
218
|
+
| Input | Effective mode | Toolset handling | Outcome/Notes |
|
|
219
|
+
| ---------------------------------------------------- | -------------- | ----------------------------------- | -------------------------------------------------------------------------------- |
|
|
220
|
+
| `startup.mode = "DYNAMIC"` (toolsets present or not) | DYNAMIC | `startup.toolsets` is ignored | Manage toolsets at runtime via meta-tools; logs a warning if `toolsets` provided |
|
|
221
|
+
| `startup.mode = "STATIC"`, `toolsets = "ALL"` | STATIC | Preload all toolsets from `catalog` | OK |
|
|
222
|
+
| `startup.mode = "STATIC"`, `toolsets = [names]` | STATIC | Validate names against `catalog` | Invalid names warn; if none valid remain → error |
|
|
223
|
+
| No `startup.mode`, `toolsets = "ALL"` | STATIC | Preload all toolsets | OK |
|
|
224
|
+
| No `startup.mode`, `toolsets = [names]` | STATIC | Validate names against `catalog` | Invalid names warn; if none valid remain → error |
|
|
225
|
+
| No `startup.mode`, no `toolsets` | DYNAMIC | No preloads | Default behavior; manage toolsets at runtime via meta-tools |
|
|
226
|
+
|
|
151
227
|
#### options.registerMetaTools (optional)
|
|
152
228
|
|
|
153
229
|
`boolean` (default: true in DYNAMIC mode; false in STATIC unless explicitly set)
|
|
@@ -158,7 +234,21 @@ Creates an MCP server with dynamic/static tool management and Fastify HTTP trans
|
|
|
158
234
|
|
|
159
235
|
`ExposurePolicy`
|
|
160
236
|
|
|
161
|
-
-
|
|
237
|
+
- Controls which toolsets can be activated and how tools are named when registered.
|
|
238
|
+
|
|
239
|
+
| Field | Type | Purpose | Example |
|
|
240
|
+
| -------------------------- | ----------------------------- | ---------------------------------------------------------------------------------- | -------------------------------------------------------------------- |
|
|
241
|
+
| `maxActiveToolsets` | `number` | Limit how many toolsets can be active at once. Prevents tool bloat. | `{ maxActiveToolsets: 1 }` blocks enabling a second toolset |
|
|
242
|
+
| `namespaceToolsWithSetKey` | `boolean` | Prefix tool names with the toolset key when registering, to avoid name collisions. | With `true`, enabling `core` registers `core.ping` instead of `ping` |
|
|
243
|
+
| `allowlist` | `string[]` | Only these toolsets may be enabled. Others are denied. | `{ allowlist: ["core"] }` prevents enabling `ext` |
|
|
244
|
+
| `denylist` | `string[]` | These toolsets cannot be enabled. | `{ denylist: ["ext"] }` blocks `ext` |
|
|
245
|
+
| `onLimitExceeded` | `(attempted, active) => void` | Callback when `maxActiveToolsets` would be exceeded. | Log or telemetry hook |
|
|
246
|
+
|
|
247
|
+
Notes
|
|
248
|
+
|
|
249
|
+
- Policy is enforced at enable time (via meta-tools or static preload).
|
|
250
|
+
- If both `allowlist` and `denylist` are present, the entry must be in `allowlist` and not in `denylist` to pass.
|
|
251
|
+
- Namespacing is applied consistently at registration time and reflected in `GET /tools`.
|
|
162
252
|
|
|
163
253
|
#### options.context (optional)
|
|
164
254
|
|
|
@@ -166,17 +256,51 @@ Creates an MCP server with dynamic/static tool management and Fastify HTTP trans
|
|
|
166
256
|
|
|
167
257
|
- Arbitrary context passed to `moduleLoaders` during tool resolution.
|
|
168
258
|
|
|
259
|
+
| Field | Type | Purpose | Example |
|
|
260
|
+
| --------- | --------- | -------------------------------------------------------------------------------------------- | -------------------------------------------------------------- |
|
|
261
|
+
| `context` | `unknown` | Extra data/injectables available to every `ModuleLoader(context)` call when resolving tools. | `{ db, cache, apiClients }` used inside loaders to build tools |
|
|
262
|
+
|
|
263
|
+
Notes
|
|
264
|
+
|
|
265
|
+
- Only `moduleLoaders` receive `context`. Direct tools defined inline in `catalog` do not.
|
|
266
|
+
- Not exposed to clients over HTTP; it stays in-process on the server.
|
|
267
|
+
- Keep it lightweight and stable; prefer passing handles (e.g., db client) rather than huge data blobs.
|
|
268
|
+
- STATIC mode: loaders are invoked at startup with the same `context`.
|
|
269
|
+
- DYNAMIC mode: loaders are invoked at enable time with the same `context`.
|
|
270
|
+
|
|
271
|
+
Example
|
|
272
|
+
|
|
273
|
+
```ts
|
|
274
|
+
const moduleLoaders = {
|
|
275
|
+
ext: async (ctx: any) => [
|
|
276
|
+
{
|
|
277
|
+
name: "echo",
|
|
278
|
+
description: "Echo using a backing service",
|
|
279
|
+
inputSchema: {
|
|
280
|
+
type: "object",
|
|
281
|
+
properties: { text: { type: "string" } },
|
|
282
|
+
required: ["text"],
|
|
283
|
+
},
|
|
284
|
+
handler: async ({ text }: { text: string }) => {
|
|
285
|
+
const result = await ctx.apiClients.echoService.send(text);
|
|
286
|
+
return { content: [{ type: "text", text: result }] } as any;
|
|
287
|
+
},
|
|
288
|
+
},
|
|
289
|
+
],
|
|
290
|
+
};
|
|
291
|
+
```
|
|
292
|
+
|
|
169
293
|
#### options.http (optional)
|
|
170
294
|
|
|
171
295
|
`{ host?: string; port?: number; basePath?: string; cors?: boolean; logger?: boolean }`
|
|
172
296
|
|
|
173
297
|
- Fastify transport configuration. Defaults: host `0.0.0.0`, port `3000`, basePath `/`, CORS enabled, logger disabled.
|
|
174
298
|
|
|
175
|
-
#### options.
|
|
299
|
+
#### options.createServer (optional)
|
|
176
300
|
|
|
177
|
-
`
|
|
301
|
+
`() => McpServer`
|
|
178
302
|
|
|
179
|
-
|
|
303
|
+
Required factory to create the SDK server instance(s).
|
|
180
304
|
|
|
181
305
|
#### options.configSchema (optional)
|
|
182
306
|
|
package/dist/index.js
CHANGED
|
@@ -1,19 +1,22 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
1
|
+
import { z as u } from "zod";
|
|
2
|
+
import p from "fastify";
|
|
3
|
+
import A from "@fastify/cors";
|
|
4
|
+
import { randomUUID as m } from "node:crypto";
|
|
5
|
+
import { StreamableHTTPServerTransport as b } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
6
|
+
import { isInitializeRequest as w } from "@modelcontextprotocol/sdk/types.js";
|
|
7
|
+
const g = {
|
|
8
|
+
dynamic: [
|
|
9
|
+
"dynamic-tool-discovery",
|
|
10
|
+
"dynamicToolDiscovery",
|
|
11
|
+
"DYNAMIC_TOOL_DISCOVERY"
|
|
12
|
+
],
|
|
10
13
|
toolsets: ["tool-sets", "toolSets", "FMP_TOOL_SETS"]
|
|
11
14
|
};
|
|
12
|
-
class
|
|
15
|
+
class S {
|
|
13
16
|
constructor(e = {}) {
|
|
14
17
|
this.keys = {
|
|
15
|
-
dynamic: e.keys?.dynamic ??
|
|
16
|
-
toolsets: e.keys?.toolsets ??
|
|
18
|
+
dynamic: e.keys?.dynamic ?? g.dynamic,
|
|
19
|
+
toolsets: e.keys?.toolsets ?? g.toolsets
|
|
17
20
|
};
|
|
18
21
|
}
|
|
19
22
|
resolveMode(e, s) {
|
|
@@ -21,31 +24,56 @@ class D {
|
|
|
21
24
|
}
|
|
22
25
|
parseCommaSeparatedToolSets(e, s) {
|
|
23
26
|
if (!e || typeof e != "string") return [];
|
|
24
|
-
const t = e.split(",").map((
|
|
25
|
-
for (const
|
|
26
|
-
o.has(
|
|
27
|
-
|
|
27
|
+
const t = e.split(",").map((i) => i.trim()).filter((i) => i.length > 0), o = new Set(Object.keys(s)), r = [];
|
|
28
|
+
for (const i of t)
|
|
29
|
+
o.has(i) ? r.push(i) : console.warn(
|
|
30
|
+
`Invalid toolset '${i}' ignored. Available: ${Array.from(
|
|
31
|
+
o
|
|
32
|
+
).join(", ")}`
|
|
33
|
+
);
|
|
34
|
+
return r;
|
|
28
35
|
}
|
|
29
36
|
getModulesForToolSets(e, s) {
|
|
30
37
|
const t = /* @__PURE__ */ new Set();
|
|
31
38
|
for (const o of e) {
|
|
32
|
-
const
|
|
33
|
-
|
|
39
|
+
const r = s[o];
|
|
40
|
+
r && (r.modules || []).forEach((i) => t.add(i));
|
|
34
41
|
}
|
|
35
42
|
return Array.from(t);
|
|
36
43
|
}
|
|
37
44
|
validateToolsetName(e, s) {
|
|
38
45
|
if (!e || typeof e != "string")
|
|
39
|
-
return {
|
|
46
|
+
return {
|
|
47
|
+
isValid: !1,
|
|
48
|
+
error: `Invalid toolset name provided. Must be a non-empty string. Available toolsets: ${Object.keys(
|
|
49
|
+
s
|
|
50
|
+
).join(", ")}`
|
|
51
|
+
};
|
|
40
52
|
const t = e.trim();
|
|
41
|
-
return t.length === 0 ? {
|
|
53
|
+
return t.length === 0 ? {
|
|
54
|
+
isValid: !1,
|
|
55
|
+
error: `Empty toolset name provided. Available toolsets: ${Object.keys(
|
|
56
|
+
s
|
|
57
|
+
).join(", ")}`
|
|
58
|
+
} : s[t] ? { isValid: !0, sanitized: t } : {
|
|
59
|
+
isValid: !1,
|
|
60
|
+
error: `Toolset '${t}' not found. Available toolsets: ${Object.keys(
|
|
61
|
+
s
|
|
62
|
+
).join(", ")}`
|
|
63
|
+
};
|
|
42
64
|
}
|
|
43
65
|
validateToolsetModules(e, s) {
|
|
44
66
|
try {
|
|
45
67
|
const t = this.getModulesForToolSets(e, s);
|
|
46
|
-
return !t || t.length === 0 ? {
|
|
68
|
+
return !t || t.length === 0 ? {
|
|
69
|
+
isValid: !1,
|
|
70
|
+
error: `No modules found for toolsets: ${e.join(", ")}`
|
|
71
|
+
} : { isValid: !0, modules: t };
|
|
47
72
|
} catch (t) {
|
|
48
|
-
return {
|
|
73
|
+
return {
|
|
74
|
+
isValid: !1,
|
|
75
|
+
error: `Error resolving modules for ${e.join(", ")}: ${t instanceof Error ? t.message : "Unknown error"}`
|
|
76
|
+
};
|
|
49
77
|
}
|
|
50
78
|
}
|
|
51
79
|
isDynamicEnabled(e) {
|
|
@@ -61,11 +89,12 @@ class D {
|
|
|
61
89
|
if (e)
|
|
62
90
|
for (const s of this.keys.toolsets) {
|
|
63
91
|
const t = e[s];
|
|
64
|
-
if (typeof t == "string" && t.trim().length > 0)
|
|
92
|
+
if (typeof t == "string" && t.trim().length > 0)
|
|
93
|
+
return t;
|
|
65
94
|
}
|
|
66
95
|
}
|
|
67
96
|
}
|
|
68
|
-
class
|
|
97
|
+
class x {
|
|
69
98
|
constructor(e) {
|
|
70
99
|
this.catalog = e.catalog, this.moduleLoaders = e.moduleLoaders ?? {};
|
|
71
100
|
}
|
|
@@ -99,18 +128,18 @@ class E {
|
|
|
99
128
|
async resolveToolsForToolsets(e, s) {
|
|
100
129
|
const t = [];
|
|
101
130
|
for (const o of e) {
|
|
102
|
-
const
|
|
103
|
-
if (
|
|
104
|
-
for (const
|
|
105
|
-
const l = this.moduleLoaders[
|
|
131
|
+
const r = this.catalog[o];
|
|
132
|
+
if (r && (Array.isArray(r.tools) && r.tools.length > 0 && t.push(...r.tools), Array.isArray(r.modules) && r.modules.length > 0))
|
|
133
|
+
for (const i of r.modules) {
|
|
134
|
+
const l = this.moduleLoaders[i];
|
|
106
135
|
if (l)
|
|
107
136
|
try {
|
|
108
|
-
const
|
|
109
|
-
Array.isArray(
|
|
110
|
-
} catch (
|
|
137
|
+
const n = await l(s);
|
|
138
|
+
Array.isArray(n) && n.length > 0 && t.push(...n);
|
|
139
|
+
} catch (n) {
|
|
111
140
|
console.warn(
|
|
112
|
-
`Module loader '${
|
|
113
|
-
|
|
141
|
+
`Module loader '${i}' failed for toolset '${o}':`,
|
|
142
|
+
n
|
|
114
143
|
);
|
|
115
144
|
}
|
|
116
145
|
}
|
|
@@ -118,12 +147,12 @@ class E {
|
|
|
118
147
|
return t;
|
|
119
148
|
}
|
|
120
149
|
}
|
|
121
|
-
class
|
|
150
|
+
class T extends Error {
|
|
122
151
|
constructor(e, s, t, o) {
|
|
123
152
|
super(e), this.name = "ToolingError", this.code = s, this.details = t;
|
|
124
153
|
}
|
|
125
154
|
}
|
|
126
|
-
class
|
|
155
|
+
class v {
|
|
127
156
|
constructor(e = {}) {
|
|
128
157
|
this.names = /* @__PURE__ */ new Set(), this.toolsetToNames = /* @__PURE__ */ new Map(), this.options = {
|
|
129
158
|
namespaceWithToolset: e.namespaceWithToolset ?? !0
|
|
@@ -137,7 +166,7 @@ class A {
|
|
|
137
166
|
}
|
|
138
167
|
add(e) {
|
|
139
168
|
if (this.names.has(e))
|
|
140
|
-
throw new
|
|
169
|
+
throw new T(
|
|
141
170
|
`Tool name collision: '${e}' already registered`,
|
|
142
171
|
"E_TOOL_NAME_CONFLICT"
|
|
143
172
|
);
|
|
@@ -152,7 +181,7 @@ class A {
|
|
|
152
181
|
return s.map((t) => {
|
|
153
182
|
const o = this.getSafeName(e, t.name);
|
|
154
183
|
if (this.has(o))
|
|
155
|
-
throw new
|
|
184
|
+
throw new T(
|
|
156
185
|
`Tool name collision for '${o}'`,
|
|
157
186
|
"E_TOOL_NAME_CONFLICT"
|
|
158
187
|
);
|
|
@@ -169,9 +198,9 @@ class A {
|
|
|
169
198
|
return e;
|
|
170
199
|
}
|
|
171
200
|
}
|
|
172
|
-
class
|
|
201
|
+
class C {
|
|
173
202
|
constructor(e) {
|
|
174
|
-
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
|
|
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 v({ namespaceWithToolset: !0 });
|
|
175
204
|
}
|
|
176
205
|
getAvailableToolsets() {
|
|
177
206
|
return this.resolver.getAvailableToolsets();
|
|
@@ -222,17 +251,17 @@ class N {
|
|
|
222
251
|
message: `Activation exceeds maxActiveToolsets (${this.exposurePolicy.maxActiveToolsets}).`
|
|
223
252
|
};
|
|
224
253
|
if (o && o.length > 0) {
|
|
225
|
-
const
|
|
254
|
+
const r = this.toolRegistry.mapAndValidate(
|
|
226
255
|
t,
|
|
227
256
|
o
|
|
228
257
|
);
|
|
229
|
-
this.registerDirectTools(
|
|
258
|
+
this.registerDirectTools(r, t);
|
|
230
259
|
}
|
|
231
260
|
this.activeToolsets.add(t);
|
|
232
261
|
try {
|
|
233
262
|
await this.onToolsListChanged?.();
|
|
234
|
-
} catch (
|
|
235
|
-
console.warn("Failed to send tool list change notification:",
|
|
263
|
+
} catch (r) {
|
|
264
|
+
console.warn("Failed to send tool list change notification:", r);
|
|
236
265
|
}
|
|
237
266
|
return {
|
|
238
267
|
success: !0,
|
|
@@ -284,19 +313,19 @@ class N {
|
|
|
284
313
|
}
|
|
285
314
|
async enableToolsets(e) {
|
|
286
315
|
const s = [];
|
|
287
|
-
for (const
|
|
316
|
+
for (const r of e)
|
|
288
317
|
try {
|
|
289
|
-
const
|
|
290
|
-
s.push({ name:
|
|
291
|
-
} catch (
|
|
318
|
+
const i = await this.enableToolset(r);
|
|
319
|
+
s.push({ name: r, ...i });
|
|
320
|
+
} catch (i) {
|
|
292
321
|
s.push({
|
|
293
|
-
name:
|
|
322
|
+
name: r,
|
|
294
323
|
success: !1,
|
|
295
|
-
message:
|
|
324
|
+
message: i instanceof Error ? i.message : "Unknown error",
|
|
296
325
|
code: "E_INTERNAL"
|
|
297
326
|
});
|
|
298
327
|
}
|
|
299
|
-
const t = s.every((
|
|
328
|
+
const t = s.every((r) => r.success), o = t ? "All toolsets enabled" : "Some toolsets failed to enable";
|
|
300
329
|
if (s.length > 0)
|
|
301
330
|
try {
|
|
302
331
|
await this.onToolsListChanged?.();
|
|
@@ -322,119 +351,154 @@ class N {
|
|
|
322
351
|
return this.enableToolsets(e);
|
|
323
352
|
}
|
|
324
353
|
}
|
|
325
|
-
function
|
|
354
|
+
function M(a, e, s) {
|
|
326
355
|
const t = s?.mode ?? "DYNAMIC";
|
|
327
|
-
|
|
356
|
+
a.tool(
|
|
328
357
|
"enable_toolset",
|
|
329
358
|
"Enable a toolset by name",
|
|
330
|
-
{ name:
|
|
359
|
+
{ name: u.string().describe("Toolset name") },
|
|
331
360
|
async (o) => {
|
|
332
|
-
const { name:
|
|
361
|
+
const { name: r } = o, i = await e.enableToolset(r);
|
|
333
362
|
return {
|
|
334
|
-
content: [{ type: "text", text: JSON.stringify(
|
|
363
|
+
content: [{ type: "text", text: JSON.stringify(i) }]
|
|
335
364
|
};
|
|
336
365
|
}
|
|
337
|
-
),
|
|
366
|
+
), a.tool(
|
|
338
367
|
"disable_toolset",
|
|
339
368
|
"Disable a toolset by name (state only)",
|
|
340
|
-
{ name:
|
|
369
|
+
{ name: u.string().describe("Toolset name") },
|
|
341
370
|
async (o) => {
|
|
342
|
-
const { name:
|
|
371
|
+
const { name: r } = o, i = await e.disableToolset(r);
|
|
343
372
|
return {
|
|
344
|
-
content: [{ type: "text", text: JSON.stringify(
|
|
373
|
+
content: [{ type: "text", text: JSON.stringify(i) }]
|
|
345
374
|
};
|
|
346
375
|
}
|
|
347
|
-
), t === "DYNAMIC" && (
|
|
376
|
+
), t === "DYNAMIC" && (a.tool(
|
|
348
377
|
"list_toolsets",
|
|
349
378
|
"List available toolsets with active status and definitions",
|
|
350
379
|
{},
|
|
351
380
|
async () => {
|
|
352
|
-
const o = e.getAvailableToolsets(),
|
|
353
|
-
const
|
|
381
|
+
const o = e.getAvailableToolsets(), r = e.getStatus().toolsetToTools, i = o.map((l) => {
|
|
382
|
+
const n = e.getToolsetDefinition(l);
|
|
354
383
|
return {
|
|
355
384
|
key: l,
|
|
356
385
|
active: e.isActive(l),
|
|
357
|
-
definition:
|
|
358
|
-
name:
|
|
359
|
-
description:
|
|
360
|
-
modules:
|
|
361
|
-
decisionCriteria:
|
|
386
|
+
definition: n ? {
|
|
387
|
+
name: n.name,
|
|
388
|
+
description: n.description,
|
|
389
|
+
modules: n.modules ?? [],
|
|
390
|
+
decisionCriteria: n.decisionCriteria ?? void 0
|
|
362
391
|
} : null,
|
|
363
|
-
tools:
|
|
392
|
+
tools: r[l] ?? []
|
|
364
393
|
};
|
|
365
394
|
});
|
|
366
395
|
return {
|
|
367
396
|
content: [
|
|
368
|
-
{ type: "text", text: JSON.stringify({ toolsets:
|
|
397
|
+
{ type: "text", text: JSON.stringify({ toolsets: i }) }
|
|
369
398
|
]
|
|
370
399
|
};
|
|
371
400
|
}
|
|
372
|
-
),
|
|
401
|
+
), a.tool(
|
|
373
402
|
"describe_toolset",
|
|
374
403
|
"Describe a toolset with definition, active status and tools",
|
|
375
|
-
{ name:
|
|
404
|
+
{ name: u.string().describe("Toolset name") },
|
|
376
405
|
async (o) => {
|
|
377
|
-
const { name:
|
|
378
|
-
if (!
|
|
406
|
+
const { name: r } = o, i = e.getToolsetDefinition(r), l = e.getStatus().toolsetToTools;
|
|
407
|
+
if (!i)
|
|
379
408
|
return {
|
|
380
409
|
content: [
|
|
381
410
|
{
|
|
382
411
|
type: "text",
|
|
383
|
-
text: JSON.stringify({ error: `Unknown toolset '${
|
|
412
|
+
text: JSON.stringify({ error: `Unknown toolset '${r}'` })
|
|
384
413
|
}
|
|
385
414
|
]
|
|
386
415
|
};
|
|
387
|
-
const
|
|
388
|
-
key:
|
|
389
|
-
active: e.isActive(
|
|
416
|
+
const n = {
|
|
417
|
+
key: r,
|
|
418
|
+
active: e.isActive(r),
|
|
390
419
|
definition: {
|
|
391
|
-
name:
|
|
392
|
-
description:
|
|
393
|
-
modules:
|
|
394
|
-
decisionCriteria:
|
|
420
|
+
name: i.name,
|
|
421
|
+
description: i.description,
|
|
422
|
+
modules: i.modules ?? [],
|
|
423
|
+
decisionCriteria: i.decisionCriteria ?? void 0
|
|
395
424
|
},
|
|
396
|
-
tools: l[
|
|
425
|
+
tools: l[r] ?? []
|
|
397
426
|
};
|
|
398
427
|
return {
|
|
399
|
-
content: [{ type: "text", text: JSON.stringify(
|
|
428
|
+
content: [{ type: "text", text: JSON.stringify(n) }]
|
|
400
429
|
};
|
|
401
430
|
}
|
|
402
|
-
)),
|
|
431
|
+
)), a.tool(
|
|
403
432
|
"list_tools",
|
|
404
433
|
"List currently registered tool names (best effort)",
|
|
405
434
|
{},
|
|
406
435
|
async () => {
|
|
407
|
-
const o = e.getStatus(),
|
|
436
|
+
const o = e.getStatus(), r = {
|
|
408
437
|
tools: o.tools,
|
|
409
438
|
toolsetToTools: o.toolsetToTools
|
|
410
439
|
};
|
|
411
440
|
return {
|
|
412
|
-
content: [{ type: "text", text: JSON.stringify(
|
|
441
|
+
content: [{ type: "text", text: JSON.stringify(r) }]
|
|
413
442
|
};
|
|
414
443
|
}
|
|
415
444
|
);
|
|
416
445
|
}
|
|
417
|
-
class
|
|
446
|
+
class y {
|
|
418
447
|
constructor(e) {
|
|
419
|
-
new
|
|
420
|
-
const s = e.startup ?? {};
|
|
421
|
-
this.mode =
|
|
448
|
+
this.toolsetValidator = new S();
|
|
449
|
+
const s = e.startup ?? {}, t = this.resolveStartupConfig(s, e.catalog);
|
|
450
|
+
this.mode = t.mode, this.resolver = new x({
|
|
422
451
|
catalog: e.catalog,
|
|
423
452
|
moduleLoaders: e.moduleLoaders
|
|
424
453
|
});
|
|
425
|
-
const
|
|
454
|
+
const o = new v({
|
|
426
455
|
namespaceWithToolset: e.exposurePolicy?.namespaceToolsWithSetKey ?? !0
|
|
427
456
|
});
|
|
428
|
-
this.manager = new
|
|
457
|
+
this.manager = new C({
|
|
429
458
|
server: e.server,
|
|
430
459
|
resolver: this.resolver,
|
|
431
460
|
context: e.context,
|
|
432
461
|
onToolsListChanged: e.notifyToolsListChanged,
|
|
433
462
|
exposurePolicy: e.exposurePolicy,
|
|
434
|
-
toolRegistry:
|
|
435
|
-
}), e.registerMetaTools !== !1 &&
|
|
436
|
-
const
|
|
437
|
-
|
|
463
|
+
toolRegistry: o
|
|
464
|
+
}), e.registerMetaTools !== !1 && M(e.server, this.manager, { mode: this.mode });
|
|
465
|
+
const r = t.toolsets;
|
|
466
|
+
r === "ALL" ? this.manager.enableToolsets(this.resolver.getAvailableToolsets()) : Array.isArray(r) && r.length > 0 && this.manager.enableToolsets(r);
|
|
467
|
+
}
|
|
468
|
+
resolveStartupConfig(e, s) {
|
|
469
|
+
if (e.mode) {
|
|
470
|
+
if (e.mode === "DYNAMIC" && e.toolsets)
|
|
471
|
+
return console.warn("startup.toolsets provided but ignored in DYNAMIC mode"), { mode: "DYNAMIC" };
|
|
472
|
+
if (e.mode === "STATIC") {
|
|
473
|
+
if (e.toolsets === "ALL")
|
|
474
|
+
return { mode: "STATIC", toolsets: "ALL" };
|
|
475
|
+
const t = Array.isArray(e.toolsets) ? e.toolsets : [], o = [];
|
|
476
|
+
for (const r of t) {
|
|
477
|
+
const { isValid: i, sanitized: l, error: n } = this.toolsetValidator.validateToolsetName(r, s);
|
|
478
|
+
i && l ? o.push(l) : n && console.warn(n);
|
|
479
|
+
}
|
|
480
|
+
if (t.length > 0 && o.length === 0)
|
|
481
|
+
throw new Error(
|
|
482
|
+
"STATIC mode requires valid toolsets or 'ALL'; none were valid"
|
|
483
|
+
);
|
|
484
|
+
return { mode: "STATIC", toolsets: o };
|
|
485
|
+
}
|
|
486
|
+
return { mode: e.mode };
|
|
487
|
+
}
|
|
488
|
+
if (e.toolsets === "ALL") return { mode: "STATIC", toolsets: "ALL" };
|
|
489
|
+
if (Array.isArray(e.toolsets) && e.toolsets.length > 0) {
|
|
490
|
+
const t = [];
|
|
491
|
+
for (const o of e.toolsets) {
|
|
492
|
+
const { isValid: r, sanitized: i, error: l } = this.toolsetValidator.validateToolsetName(o, s);
|
|
493
|
+
r && i ? t.push(i) : l && console.warn(l);
|
|
494
|
+
}
|
|
495
|
+
if (t.length === 0)
|
|
496
|
+
throw new Error(
|
|
497
|
+
"STATIC mode requires valid toolsets or 'ALL'; none were valid"
|
|
498
|
+
);
|
|
499
|
+
return { mode: "STATIC", toolsets: t };
|
|
500
|
+
}
|
|
501
|
+
return { mode: "DYNAMIC" };
|
|
438
502
|
}
|
|
439
503
|
getMode() {
|
|
440
504
|
return this.mode;
|
|
@@ -443,7 +507,7 @@ class b {
|
|
|
443
507
|
return this.manager;
|
|
444
508
|
}
|
|
445
509
|
}
|
|
446
|
-
class
|
|
510
|
+
class I {
|
|
447
511
|
constructor(e = {}) {
|
|
448
512
|
this.storage = /* @__PURE__ */ new Map(), this.maxSize = e.maxSize ?? 1e3, this.ttlMs = e.ttlMs ?? 1e3 * 60 * 60;
|
|
449
513
|
const s = e.pruneIntervalMs ?? 1e3 * 60 * 10;
|
|
@@ -483,9 +547,9 @@ class j {
|
|
|
483
547
|
e - t.lastAccessed > this.ttlMs && this.delete(s);
|
|
484
548
|
}
|
|
485
549
|
}
|
|
486
|
-
class
|
|
550
|
+
class L {
|
|
487
551
|
constructor(e, s, t = {}, o) {
|
|
488
|
-
this.app = null, this.clientCache = new
|
|
552
|
+
this.app = null, this.clientCache = new I(), this.defaultManager = e, this.createBundle = s, this.options = {
|
|
489
553
|
host: t.host ?? "0.0.0.0",
|
|
490
554
|
port: t.port ?? 3e3,
|
|
491
555
|
basePath: t.basePath ?? "/",
|
|
@@ -496,8 +560,8 @@ class O {
|
|
|
496
560
|
}
|
|
497
561
|
async start() {
|
|
498
562
|
if (this.app) return;
|
|
499
|
-
const e = this.options.app ??
|
|
500
|
-
this.options.cors && await e.register(
|
|
563
|
+
const e = this.options.app ?? p({ logger: this.options.logger });
|
|
564
|
+
this.options.cors && await e.register(A, { origin: !0 });
|
|
501
565
|
const s = this.options.basePath.endsWith("/") ? this.options.basePath.slice(0, -1) : this.options.basePath;
|
|
502
566
|
e.get(`${s}/healthz`, async () => ({ ok: !0 })), e.get(`${s}/tools`, async () => this.defaultManager.getStatus()), e.get(`${s}/.well-known/mcp-config`, async (t, o) => (o.header("Content-Type", "application/schema+json; charset=utf-8"), this.configSchema ?? {
|
|
503
567
|
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
@@ -511,30 +575,30 @@ class O {
|
|
|
511
575
|
})), e.post(
|
|
512
576
|
`${s}/mcp`,
|
|
513
577
|
async (t, o) => {
|
|
514
|
-
const
|
|
515
|
-
let
|
|
516
|
-
if (!
|
|
517
|
-
const
|
|
518
|
-
|
|
519
|
-
server:
|
|
520
|
-
orchestrator:
|
|
578
|
+
const r = t.headers["mcp-client-id"]?.trim(), i = r && r.length > 0 ? r : `anon-${m()}`, l = !i.startsWith("anon-");
|
|
579
|
+
let n = l ? this.clientCache.get(i) : null;
|
|
580
|
+
if (!n) {
|
|
581
|
+
const h = this.createBundle();
|
|
582
|
+
n = {
|
|
583
|
+
server: h.server,
|
|
584
|
+
orchestrator: h.orchestrator,
|
|
521
585
|
sessions: /* @__PURE__ */ new Map()
|
|
522
|
-
}, l && this.clientCache.set(
|
|
586
|
+
}, l && this.clientCache.set(i, n);
|
|
523
587
|
}
|
|
524
|
-
const
|
|
525
|
-
let
|
|
526
|
-
if (
|
|
527
|
-
|
|
528
|
-
else if (!
|
|
529
|
-
const
|
|
530
|
-
|
|
531
|
-
sessionIdGenerator: () =>
|
|
532
|
-
onsessioninitialized: (
|
|
533
|
-
|
|
588
|
+
const c = t.headers["mcp-session-id"];
|
|
589
|
+
let d;
|
|
590
|
+
if (c && n.sessions.get(c))
|
|
591
|
+
d = n.sessions.get(c);
|
|
592
|
+
else if (!c && w(t.body)) {
|
|
593
|
+
const h = m();
|
|
594
|
+
d = new b({
|
|
595
|
+
sessionIdGenerator: () => h,
|
|
596
|
+
onsessioninitialized: (f) => {
|
|
597
|
+
n.sessions.set(f, d);
|
|
534
598
|
}
|
|
535
599
|
});
|
|
536
600
|
try {
|
|
537
|
-
await
|
|
601
|
+
await n.server.connect(d);
|
|
538
602
|
} catch {
|
|
539
603
|
return o.code(500), {
|
|
540
604
|
jsonrpc: "2.0",
|
|
@@ -542,8 +606,8 @@ class O {
|
|
|
542
606
|
id: null
|
|
543
607
|
};
|
|
544
608
|
}
|
|
545
|
-
|
|
546
|
-
|
|
609
|
+
d.onclose = () => {
|
|
610
|
+
d?.sessionId && n.sessions.delete(d.sessionId);
|
|
547
611
|
};
|
|
548
612
|
} else
|
|
549
613
|
return o.code(400), {
|
|
@@ -551,29 +615,29 @@ class O {
|
|
|
551
615
|
error: { code: -32e3, message: "Session not found or expired" },
|
|
552
616
|
id: null
|
|
553
617
|
};
|
|
554
|
-
return await
|
|
618
|
+
return await d.handleRequest(
|
|
555
619
|
t.raw,
|
|
556
620
|
o.raw,
|
|
557
621
|
t.body
|
|
558
622
|
), o;
|
|
559
623
|
}
|
|
560
624
|
), e.get(`${s}/mcp`, async (t, o) => {
|
|
561
|
-
const
|
|
562
|
-
if (!
|
|
625
|
+
const r = t.headers["mcp-client-id"]?.trim(), i = r && r.length > 0 ? r : "";
|
|
626
|
+
if (!i)
|
|
563
627
|
return o.code(400), "Missing mcp-client-id";
|
|
564
|
-
const l = this.clientCache.get(
|
|
628
|
+
const l = this.clientCache.get(i);
|
|
565
629
|
if (!l)
|
|
566
630
|
return o.code(400), "Invalid or expired client";
|
|
567
|
-
const
|
|
568
|
-
if (!
|
|
631
|
+
const n = t.headers["mcp-session-id"];
|
|
632
|
+
if (!n)
|
|
569
633
|
return o.code(400), "Missing mcp-session-id";
|
|
570
|
-
const
|
|
571
|
-
return
|
|
634
|
+
const c = l.sessions.get(n);
|
|
635
|
+
return c ? (await c.handleRequest(t.raw, o.raw), o) : (o.code(400), "Invalid or expired session ID");
|
|
572
636
|
}), e.delete(
|
|
573
637
|
`${s}/mcp`,
|
|
574
638
|
async (t, o) => {
|
|
575
|
-
const
|
|
576
|
-
if (!
|
|
639
|
+
const r = t.headers["mcp-client-id"]?.trim(), i = r && r.length > 0 ? r : "", l = t.headers["mcp-session-id"];
|
|
640
|
+
if (!i || !l)
|
|
577
641
|
return o.code(400), {
|
|
578
642
|
jsonrpc: "2.0",
|
|
579
643
|
error: {
|
|
@@ -582,8 +646,8 @@ class O {
|
|
|
582
646
|
},
|
|
583
647
|
id: null
|
|
584
648
|
};
|
|
585
|
-
const
|
|
586
|
-
return !
|
|
649
|
+
const n = this.clientCache.get(i), c = n?.sessions.get(l);
|
|
650
|
+
return !n || !c ? (o.code(404), {
|
|
587
651
|
jsonrpc: "2.0",
|
|
588
652
|
error: { code: -32e3, message: "Session not found or expired" },
|
|
589
653
|
id: null
|
|
@@ -595,77 +659,59 @@ class O {
|
|
|
595
659
|
this.app && (this.options.app || await this.app.close(), this.app = null);
|
|
596
660
|
}
|
|
597
661
|
}
|
|
598
|
-
async function
|
|
599
|
-
const e =
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
// listChanged is internal-only and computed by mode
|
|
604
|
-
listChanged: e === "DYNAMIC"
|
|
605
|
-
}
|
|
606
|
-
}, r = new y({
|
|
607
|
-
name: s,
|
|
608
|
-
version: t,
|
|
609
|
-
capabilities: i
|
|
610
|
-
}), l = (c) => typeof c?.server?.notification == "function", a = (c) => typeof c?.notifyToolsListChanged == "function", d = async (c) => {
|
|
662
|
+
async function j(a) {
|
|
663
|
+
const e = a.startup?.mode ?? "DYNAMIC";
|
|
664
|
+
if (typeof a.createServer != "function")
|
|
665
|
+
throw new Error("createMcpServer: `createServer` (factory) is required");
|
|
666
|
+
const s = a.createServer(), t = (n) => typeof n?.server?.notification == "function", o = (n) => typeof n?.notifyToolsListChanged == "function", r = async (n) => {
|
|
611
667
|
try {
|
|
612
|
-
if (
|
|
613
|
-
await
|
|
668
|
+
if (t(n)) {
|
|
669
|
+
await n.server.notification({
|
|
614
670
|
method: "notifications/tools/list_changed"
|
|
615
671
|
});
|
|
616
672
|
return;
|
|
617
673
|
}
|
|
618
|
-
|
|
674
|
+
o(n) && await n.notifyToolsListChanged();
|
|
619
675
|
} catch {
|
|
620
676
|
}
|
|
621
|
-
},
|
|
622
|
-
server:
|
|
623
|
-
catalog:
|
|
624
|
-
moduleLoaders:
|
|
625
|
-
exposurePolicy:
|
|
626
|
-
context:
|
|
627
|
-
notifyToolsListChanged: async () =>
|
|
628
|
-
startup:
|
|
629
|
-
registerMetaTools:
|
|
630
|
-
}),
|
|
631
|
-
|
|
677
|
+
}, i = new y({
|
|
678
|
+
server: s,
|
|
679
|
+
catalog: a.catalog,
|
|
680
|
+
moduleLoaders: a.moduleLoaders,
|
|
681
|
+
exposurePolicy: a.exposurePolicy,
|
|
682
|
+
context: a.context,
|
|
683
|
+
notifyToolsListChanged: async () => r(s),
|
|
684
|
+
startup: a.startup,
|
|
685
|
+
registerMetaTools: a.registerMetaTools !== void 0 ? a.registerMetaTools : e === "DYNAMIC"
|
|
686
|
+
}), l = new L(
|
|
687
|
+
i.getManager(),
|
|
632
688
|
() => {
|
|
633
|
-
const
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
capabilities: M
|
|
643
|
-
}), C = new b({
|
|
644
|
-
server: m,
|
|
645
|
-
catalog: n.catalog,
|
|
646
|
-
moduleLoaders: n.moduleLoaders,
|
|
647
|
-
exposurePolicy: n.exposurePolicy,
|
|
648
|
-
context: n.context,
|
|
649
|
-
notifyToolsListChanged: async () => d(m),
|
|
650
|
-
startup: n.startup,
|
|
651
|
-
registerMetaTools: n.registerMetaTools !== void 0 ? n.registerMetaTools : c === "DYNAMIC"
|
|
689
|
+
const n = e === "DYNAMIC" ? a.createServer() : s, c = new y({
|
|
690
|
+
server: n,
|
|
691
|
+
catalog: a.catalog,
|
|
692
|
+
moduleLoaders: a.moduleLoaders,
|
|
693
|
+
exposurePolicy: a.exposurePolicy,
|
|
694
|
+
context: a.context,
|
|
695
|
+
notifyToolsListChanged: async () => r(n),
|
|
696
|
+
startup: a.startup,
|
|
697
|
+
registerMetaTools: a.registerMetaTools !== void 0 ? a.registerMetaTools : e === "DYNAMIC"
|
|
652
698
|
});
|
|
653
|
-
return { server:
|
|
699
|
+
return { server: n, orchestrator: c };
|
|
654
700
|
},
|
|
655
|
-
|
|
656
|
-
|
|
701
|
+
a.http,
|
|
702
|
+
a.configSchema
|
|
657
703
|
);
|
|
658
704
|
return {
|
|
659
|
-
server:
|
|
705
|
+
server: s,
|
|
660
706
|
start: async () => {
|
|
661
|
-
await
|
|
707
|
+
await l.start();
|
|
662
708
|
},
|
|
663
709
|
close: async () => {
|
|
664
|
-
await
|
|
710
|
+
await l.stop();
|
|
665
711
|
}
|
|
666
712
|
};
|
|
667
713
|
}
|
|
668
714
|
export {
|
|
669
|
-
|
|
715
|
+
j as createMcpServer
|
|
670
716
|
};
|
|
671
717
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../src/mode/ModeResolver.ts","../src/mode/ModuleResolver.ts","../src/errors/ToolingError.ts","../src/core/ToolRegistry.ts","../src/core/DynamicToolManager.ts","../src/meta/registerMetaTools.ts","../src/core/ServerOrchestrator.ts","../src/session/ClientResourceCache.ts","../src/http/FastifyTransport.ts","../src/server/createMcpServer.ts"],"sourcesContent":["import type { Mode, ToolSetCatalog } from \"../types/index.js\";\n\nexport interface ModeResolverKeys {\n dynamic?: string[]; // keys that, when present/true, enable dynamic mode\n toolsets?: string[]; // keys that carry comma-separated toolsets\n}\n\nexport interface ModeResolverOptions {\n keys?: ModeResolverKeys;\n}\n\nconst DEFAULT_KEYS: Required<ModeResolverKeys> = {\n dynamic: [\"dynamic-tool-discovery\", \"dynamicToolDiscovery\", \"DYNAMIC_TOOL_DISCOVERY\"],\n toolsets: [\"tool-sets\", \"toolSets\", \"FMP_TOOL_SETS\"],\n};\n\nexport class ModeResolver {\n private readonly keys: Required<ModeResolverKeys>;\n\n constructor(options: ModeResolverOptions = {}) {\n this.keys = {\n dynamic: options.keys?.dynamic ?? DEFAULT_KEYS.dynamic,\n toolsets: options.keys?.toolsets ?? DEFAULT_KEYS.toolsets,\n };\n }\n\n public resolveMode(env?: Record<string, string | undefined>, args?: Record<string, unknown>): Mode | null {\n // Check args first\n if (this.isDynamicEnabled(args)) return \"DYNAMIC\";\n\n const toolsetsFromArgs = this.getToolsetsString(args);\n if (toolsetsFromArgs) return \"STATIC\";\n\n // Check env next\n if (this.isDynamicEnabled(env)) return \"DYNAMIC\";\n\n const toolsetsFromEnv = this.getToolsetsString(env);\n if (toolsetsFromEnv) return \"STATIC\";\n\n return null; // no override\n }\n\n public parseCommaSeparatedToolSets(input: string, catalog: ToolSetCatalog): string[] {\n if (!input || typeof input !== \"string\") return [];\n const raw = input\n .split(\",\")\n .map((s) => s.trim())\n .filter((s) => s.length > 0);\n\n const valid = new Set(Object.keys(catalog));\n const result: string[] = [];\n for (const name of raw) {\n if (valid.has(name)) result.push(name);\n else console.warn(`Invalid toolset '${name}' ignored. Available: ${Array.from(valid).join(\", \")}`);\n }\n return result;\n }\n\n public getModulesForToolSets(toolsets: string[], catalog: ToolSetCatalog): string[] {\n const modules = new Set<string>();\n for (const name of toolsets) {\n const def = catalog[name];\n if (!def) continue;\n (def.modules || []).forEach((m) => modules.add(m));\n }\n return Array.from(modules);\n }\n\n public validateToolsetName(name: unknown, catalog: ToolSetCatalog): { isValid: boolean; sanitized?: string; error?: string } {\n if (!name || typeof name !== \"string\") {\n return { isValid: false, error: `Invalid toolset name provided. Must be a non-empty string. Available toolsets: ${Object.keys(catalog).join(\", \")}` };\n }\n const sanitized = name.trim();\n if (sanitized.length === 0) {\n return { isValid: false, error: `Empty toolset name provided. Available toolsets: ${Object.keys(catalog).join(\", \")}` };\n }\n if (!catalog[sanitized]) {\n return { isValid: false, error: `Toolset '${sanitized}' not found. Available toolsets: ${Object.keys(catalog).join(\", \")}` };\n }\n return { isValid: true, sanitized };\n }\n\n public validateToolsetModules(toolsetNames: string[], catalog: ToolSetCatalog): { isValid: boolean; modules?: string[]; error?: string } {\n try {\n const modules = this.getModulesForToolSets(toolsetNames, catalog);\n if (!modules || modules.length === 0) {\n return { isValid: false, error: `No modules found for toolsets: ${toolsetNames.join(\", \")}` };\n }\n return { isValid: true, modules };\n } catch (error) {\n return { isValid: false, error: `Error resolving modules for ${toolsetNames.join(\", \")}: ${error instanceof Error ? error.message : \"Unknown error\"}` };\n }\n }\n\n private isDynamicEnabled(source?: Record<string, unknown> | Record<string, string | undefined>): boolean {\n if (!source) return false;\n for (const key of this.keys.dynamic) {\n const value = (source as any)[key];\n if (value === true) return true;\n if (typeof value === \"string\") {\n const v = value.trim().toLowerCase();\n if (v === \"true\") return true;\n }\n }\n return false;\n }\n\n private getToolsetsString(source?: Record<string, unknown> | Record<string, string | undefined>): string | undefined {\n if (!source) return undefined;\n for (const key of this.keys.toolsets) {\n const value = (source as any)[key];\n if (typeof value === \"string\" && value.trim().length > 0) return value as string;\n }\n return undefined;\n }\n}\n\n","import type {\n ToolSetCatalog,\n ToolSetDefinition,\n McpToolDefinition,\n ModuleLoader,\n} from \"../types/index.js\";\n\nexport interface ModuleResolverOptions {\n catalog: ToolSetCatalog;\n moduleLoaders?: Record<string, ModuleLoader>;\n}\n\nexport class ModuleResolver {\n private readonly catalog: ToolSetCatalog;\n private readonly moduleLoaders: Record<string, ModuleLoader>;\n\n constructor(options: ModuleResolverOptions) {\n this.catalog = options.catalog;\n this.moduleLoaders = options.moduleLoaders ?? {};\n }\n\n public getAvailableToolsets(): string[] {\n return Object.keys(this.catalog);\n }\n\n public getToolsetDefinition(name: string): ToolSetDefinition | undefined {\n return this.catalog[name];\n }\n\n public validateToolsetName(name: unknown): {\n isValid: boolean;\n sanitized?: string;\n error?: string;\n } {\n if (!name || typeof name !== \"string\") {\n return {\n isValid: false,\n error: `Invalid toolset name provided. Must be a non-empty string. Available toolsets: ${this.getAvailableToolsets().join(\n \", \"\n )}`,\n };\n }\n const sanitized = name.trim();\n if (sanitized.length === 0) {\n return {\n isValid: false,\n error: `Empty toolset name provided. Available toolsets: ${this.getAvailableToolsets().join(\n \", \"\n )}`,\n };\n }\n if (!this.catalog[sanitized]) {\n return {\n isValid: false,\n error: `Toolset '${sanitized}' not found. Available toolsets: ${this.getAvailableToolsets().join(\n \", \"\n )}`,\n };\n }\n return { isValid: true, sanitized };\n }\n\n public async resolveToolsForToolsets(\n toolsets: string[],\n context?: unknown\n ): Promise<McpToolDefinition[]> {\n const collected: McpToolDefinition[] = [];\n for (const name of toolsets) {\n const def = this.catalog[name];\n if (!def) continue;\n if (Array.isArray(def.tools) && def.tools.length > 0) {\n collected.push(...def.tools);\n }\n if (Array.isArray(def.modules) && def.modules.length > 0) {\n for (const modKey of def.modules) {\n const loader = this.moduleLoaders[modKey];\n if (!loader) continue;\n try {\n const loaded = await loader(context);\n if (Array.isArray(loaded) && loaded.length > 0) {\n collected.push(...loaded);\n }\n } catch (err) {\n console.warn(\n `Module loader '${modKey}' failed for toolset '${name}':`,\n err\n );\n }\n }\n }\n }\n return collected;\n }\n}\n","import type { ToolingErrorCode } from \"../types/index.js\";\n\nexport class ToolingError extends Error {\n public readonly code: ToolingErrorCode;\n public readonly details?: Record<string, unknown>;\n\n constructor(\n message: string,\n code: ToolingErrorCode,\n details?: Record<string, unknown>,\n _options?: unknown\n ) {\n super(message);\n this.name = \"ToolingError\";\n this.code = code;\n this.details = details;\n }\n}\n","import type { McpToolDefinition } from \"../types/index.js\";\nimport { ToolingError } from \"../errors/ToolingError.js\";\n\nexport interface ToolRegistryOptions {\n namespaceWithToolset?: boolean;\n}\n\nexport class ToolRegistry {\n private readonly options: Required<ToolRegistryOptions>;\n private readonly names = new Set<string>();\n private readonly toolsetToNames = new Map<string, Set<string>>();\n\n constructor(options: ToolRegistryOptions = {}) {\n this.options = {\n namespaceWithToolset: options.namespaceWithToolset ?? true,\n };\n }\n\n public getSafeName(toolsetKey: string, toolName: string): string {\n if (!this.options.namespaceWithToolset) return toolName;\n if (toolName.startsWith(`${toolsetKey}.`)) return toolName;\n return `${toolsetKey}.${toolName}`;\n }\n\n public has(name: string): boolean {\n return this.names.has(name);\n }\n\n public add(name: string): void {\n if (this.names.has(name)) {\n throw new ToolingError(\n `Tool name collision: '${name}' already registered`,\n \"E_TOOL_NAME_CONFLICT\"\n );\n }\n this.names.add(name);\n }\n\n public addForToolset(toolsetKey: string, name: string): void {\n this.add(name);\n const set = this.toolsetToNames.get(toolsetKey) ?? new Set<string>();\n set.add(name);\n this.toolsetToNames.set(toolsetKey, set);\n }\n\n public mapAndValidate(\n toolsetKey: string,\n tools: McpToolDefinition[]\n ): McpToolDefinition[] {\n return tools.map((t) => {\n const safe = this.getSafeName(toolsetKey, t.name);\n if (this.has(safe)) {\n throw new ToolingError(\n `Tool name collision for '${safe}'`,\n \"E_TOOL_NAME_CONFLICT\"\n );\n }\n return { ...t, name: safe };\n });\n }\n\n public list(): string[] {\n return Array.from(this.names);\n }\n\n public listByToolset(): Record<string, string[]> {\n const result: Record<string, string[]> = {};\n for (const [k, v] of this.toolsetToNames.entries()) {\n result[k] = Array.from(v);\n }\n return result;\n }\n}\n","import type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport type {\n ExposurePolicy,\n McpToolDefinition,\n ToolSetDefinition,\n ToolingErrorCode,\n} from \"../types/index.js\";\nimport { ModuleResolver } from \"../mode/ModuleResolver.js\";\nimport { ToolRegistry } from \"./ToolRegistry.js\";\n\nexport interface DynamicToolManagerOptions {\n server: McpServer;\n resolver: ModuleResolver;\n context?: unknown;\n onToolsListChanged?: () => Promise<void> | void;\n exposurePolicy?: ExposurePolicy;\n toolRegistry?: ToolRegistry;\n}\n\nexport class DynamicToolManager {\n private readonly server: McpServer;\n private readonly resolver: ModuleResolver;\n private readonly context?: unknown;\n private readonly onToolsListChanged?: () => Promise<void> | void;\n private readonly exposurePolicy?: ExposurePolicy;\n private readonly toolRegistry: ToolRegistry;\n\n private readonly activeToolsets = new Set<string>();\n\n constructor(options: DynamicToolManagerOptions) {\n this.server = options.server;\n this.resolver = options.resolver;\n this.context = options.context;\n this.onToolsListChanged = options.onToolsListChanged;\n this.exposurePolicy = options.exposurePolicy;\n this.toolRegistry =\n options.toolRegistry ?? new ToolRegistry({ namespaceWithToolset: true });\n }\n\n public getAvailableToolsets(): string[] {\n return this.resolver.getAvailableToolsets();\n }\n\n public getActiveToolsets(): string[] {\n return Array.from(this.activeToolsets);\n }\n\n public getToolsetDefinition(name: string): ToolSetDefinition | undefined {\n return this.resolver.getToolsetDefinition(name);\n }\n\n public isActive(name: string): boolean {\n return this.activeToolsets.has(name);\n }\n\n public async enableToolset(\n toolsetName: string\n ): Promise<{ success: boolean; message: string }> {\n const validation = this.resolver.validateToolsetName(toolsetName);\n if (!validation.isValid || !validation.sanitized) {\n return {\n success: false,\n message: validation.error || \"Unknown validation error\",\n };\n }\n const sanitized = validation.sanitized;\n if (this.activeToolsets.has(sanitized)) {\n return {\n success: false,\n message: `Toolset '${sanitized}' is already enabled.`,\n };\n }\n\n try {\n const resolvedTools = await this.resolver.resolveToolsForToolsets(\n [sanitized],\n this.context\n );\n\n // Exposure policy checks\n if (\n this.exposurePolicy?.allowlist &&\n !this.exposurePolicy.allowlist.includes(sanitized)\n ) {\n return {\n success: false,\n message: `Toolset '${sanitized}' is not allowed by policy.`,\n };\n }\n if (\n this.exposurePolicy?.denylist &&\n this.exposurePolicy.denylist.includes(sanitized)\n ) {\n return {\n success: false,\n message: `Toolset '${sanitized}' is denied by policy.`,\n };\n }\n if (this.exposurePolicy?.maxActiveToolsets !== undefined) {\n const next = this.activeToolsets.size + 1;\n if (next > this.exposurePolicy.maxActiveToolsets) {\n this.exposurePolicy.onLimitExceeded?.(\n [sanitized],\n Array.from(this.activeToolsets)\n );\n return {\n success: false,\n message: `Activation exceeds maxActiveToolsets (${this.exposurePolicy.maxActiveToolsets}).`,\n };\n }\n }\n\n // Register all resolved tools (direct + module-derived)\n if (resolvedTools && resolvedTools.length > 0) {\n const mapped = this.toolRegistry.mapAndValidate(\n sanitized,\n resolvedTools\n );\n this.registerDirectTools(mapped, sanitized);\n }\n\n // Track state (modules no longer tracked)\n this.activeToolsets.add(sanitized);\n\n // Notify list change\n try {\n await this.onToolsListChanged?.();\n } catch (err) {\n console.warn(`Failed to send tool list change notification:`, err);\n }\n\n return {\n success: true,\n message: `Toolset '${sanitized}' enabled successfully. Registered ${\n resolvedTools?.length ?? 0\n } tools.`,\n };\n } catch (error) {\n this.activeToolsets.delete(sanitized);\n return {\n success: false,\n message: `Failed to enable toolset '${sanitized}': ${\n error instanceof Error ? error.message : \"Unknown error\"\n }`,\n };\n }\n }\n\n public async disableToolset(\n toolsetName: string\n ): Promise<{ success: boolean; message: string }> {\n const validation = this.resolver.validateToolsetName(toolsetName);\n if (!validation.isValid || !validation.sanitized) {\n const activeToolsets =\n Array.from(this.activeToolsets).join(\", \") || \"none\";\n const base = validation.error || \"Unknown validation error\";\n return {\n success: false,\n message: `${base} Active toolsets: ${activeToolsets}`,\n };\n }\n const sanitized = validation.sanitized;\n if (!this.activeToolsets.has(sanitized)) {\n return {\n success: false,\n message: `Toolset '${sanitized}' is not currently active. Active toolsets: ${\n Array.from(this.activeToolsets).join(\", \") || \"none\"\n }`,\n };\n }\n\n // State-only disable; no unregistration support in MCP\n this.activeToolsets.delete(sanitized);\n\n try {\n await this.onToolsListChanged?.();\n } catch (err) {\n console.warn(`Failed to send tool list change notification:`, err);\n }\n\n return {\n success: true,\n message: `Toolset '${sanitized}' disabled successfully. Individual tools remain registered due to MCP limitations.`,\n };\n }\n\n public getStatus() {\n return {\n availableToolsets: this.getAvailableToolsets(),\n activeToolsets: this.getActiveToolsets(),\n registeredModules: [],\n totalToolsets: this.getAvailableToolsets().length,\n activeCount: this.activeToolsets.size,\n tools: this.toolRegistry.list(),\n toolsetToTools: this.toolRegistry.listByToolset(),\n };\n }\n\n public async enableToolsets(toolsetNames: string[]): Promise<{\n success: boolean;\n results: Array<{\n name: string;\n success: boolean;\n message: string;\n code?: ToolingErrorCode;\n }>;\n message: string;\n }> {\n const results: Array<{\n name: string;\n success: boolean;\n message: string;\n code?: ToolingErrorCode;\n }> = [];\n for (const name of toolsetNames) {\n try {\n const res = await this.enableToolset(name);\n results.push({ name, ...res });\n } catch (err) {\n results.push({\n name,\n success: false,\n message: err instanceof Error ? err.message : \"Unknown error\",\n code: \"E_INTERNAL\",\n });\n }\n }\n const successAll = results.every((r) => r.success);\n const message = successAll\n ? \"All toolsets enabled\"\n : \"Some toolsets failed to enable\";\n if (results.length > 0) {\n try {\n await this.onToolsListChanged?.();\n } catch {}\n }\n return { success: successAll, results, message };\n }\n\n private registerDirectTools(\n tools: McpToolDefinition[],\n toolsetKey?: string\n ): void {\n for (const tool of tools) {\n try {\n this.server.tool(\n tool.name,\n tool.description,\n tool.inputSchema as any,\n async (args: any) => {\n return await tool.handler(args);\n }\n );\n if (toolsetKey) this.toolRegistry.addForToolset(toolsetKey, tool.name);\n else this.toolRegistry.add(tool.name);\n } catch (err) {\n console.error(`Failed to register direct tool '${tool.name}':`, err);\n throw err;\n }\n }\n }\n\n public async enableAllToolsets(): Promise<{\n success: boolean;\n results: Array<{\n name: string;\n success: boolean;\n message: string;\n code?: ToolingErrorCode;\n }>;\n message: string;\n }> {\n const all = this.getAvailableToolsets();\n return this.enableToolsets(all);\n }\n}\n","import type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport type { Mode } from \"../types/index.js\";\nimport { z } from \"zod\";\nimport { DynamicToolManager } from \"../core/DynamicToolManager.js\";\n\nexport function registerMetaTools(\n server: McpServer,\n manager: DynamicToolManager,\n options?: { mode?: Exclude<Mode, \"ALL\"> }\n): void {\n const mode = options?.mode ?? \"DYNAMIC\";\n // list_tools is always available\n server.tool(\n \"enable_toolset\",\n \"Enable a toolset by name\",\n { name: z.string().describe(\"Toolset name\") },\n async (args: any) => {\n const { name } = args as { name: string };\n const result = await manager.enableToolset(name);\n return {\n content: [{ type: \"text\", text: JSON.stringify(result) }],\n } as any;\n }\n );\n\n server.tool(\n \"disable_toolset\",\n \"Disable a toolset by name (state only)\",\n { name: z.string().describe(\"Toolset name\") },\n async (args: any) => {\n const { name } = args as { name: string };\n const result = await manager.disableToolset(name);\n return {\n content: [{ type: \"text\", text: JSON.stringify(result) }],\n } as any;\n }\n );\n\n if (mode === \"DYNAMIC\") {\n server.tool(\n \"list_toolsets\",\n \"List available toolsets with active status and definitions\",\n {},\n async () => {\n const available = manager.getAvailableToolsets();\n const byToolset = manager.getStatus().toolsetToTools;\n const items = available.map((key) => {\n const def = manager.getToolsetDefinition(key);\n return {\n key,\n active: manager.isActive(key),\n definition: def\n ? {\n name: def.name,\n description: def.description,\n modules: def.modules ?? [],\n decisionCriteria: def.decisionCriteria ?? undefined,\n }\n : null,\n tools: byToolset[key] ?? [],\n };\n });\n return {\n content: [\n { type: \"text\", text: JSON.stringify({ toolsets: items }) },\n ],\n } as any;\n }\n );\n\n server.tool(\n \"describe_toolset\",\n \"Describe a toolset with definition, active status and tools\",\n { name: z.string().describe(\"Toolset name\") },\n async (args: any) => {\n const { name } = args as { name: string };\n const def = manager.getToolsetDefinition(name);\n const byToolset = manager.getStatus().toolsetToTools;\n if (!def) {\n return {\n content: [\n {\n type: \"text\",\n text: JSON.stringify({ error: `Unknown toolset '${name}'` }),\n },\n ],\n } as any;\n }\n const payload = {\n key: name,\n active: manager.isActive(name),\n definition: {\n name: def.name,\n description: def.description,\n modules: def.modules ?? [],\n decisionCriteria: def.decisionCriteria ?? undefined,\n },\n tools: byToolset[name] ?? [],\n };\n return {\n content: [{ type: \"text\", text: JSON.stringify(payload) }],\n } as any;\n }\n );\n }\n\n server.tool(\n \"list_tools\",\n \"List currently registered tool names (best effort)\",\n {},\n async () => {\n const status = manager.getStatus();\n const payload = {\n tools: status.tools,\n toolsetToTools: status.toolsetToTools,\n };\n return {\n content: [{ type: \"text\", text: JSON.stringify(payload) }],\n } as any;\n }\n );\n}\n","import type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { ModeResolver } from \"../mode/ModeResolver.js\";\nimport { ModuleResolver } from \"../mode/ModuleResolver.js\";\nimport { DynamicToolManager } from \"./DynamicToolManager.js\";\nimport { registerMetaTools } from \"../meta/registerMetaTools.js\";\nimport type { ExposurePolicy, Mode, ToolSetCatalog } from \"../types/index.js\";\nimport { ToolRegistry } from \"./ToolRegistry.js\";\n\nexport interface ServerOrchestratorOptions {\n server: McpServer;\n catalog: ToolSetCatalog;\n moduleLoaders?: Record<string, any>;\n exposurePolicy?: ExposurePolicy;\n context?: unknown;\n notifyToolsListChanged?: () => Promise<void> | void;\n startup?: { mode?: Exclude<Mode, \"ALL\">; toolsets?: string[] | \"ALL\" };\n registerMetaTools?: boolean;\n}\n\nexport class ServerOrchestrator {\n private readonly mode: Exclude<Mode, \"ALL\">;\n private readonly resolver: ModuleResolver;\n private readonly manager: DynamicToolManager;\n\n constructor(options: ServerOrchestratorOptions) {\n const modeResolver = new ModeResolver();\n const startup = options.startup ?? {};\n this.mode = startup.mode ?? \"DYNAMIC\";\n this.resolver = new ModuleResolver({\n catalog: options.catalog,\n moduleLoaders: options.moduleLoaders as any,\n });\n const toolRegistry = new ToolRegistry({\n namespaceWithToolset:\n options.exposurePolicy?.namespaceToolsWithSetKey ?? true,\n });\n this.manager = new DynamicToolManager({\n server: options.server,\n resolver: this.resolver,\n context: options.context,\n onToolsListChanged: options.notifyToolsListChanged,\n exposurePolicy: options.exposurePolicy,\n toolRegistry,\n });\n\n // Register meta-tools only if requested (default true)\n if (options.registerMetaTools !== false) {\n registerMetaTools(options.server, this.manager, { mode: this.mode });\n }\n\n // Startup behavior\n const initial = startup.toolsets;\n if (initial === \"ALL\") {\n void this.manager.enableToolsets(this.resolver.getAvailableToolsets());\n } else if (Array.isArray(initial) && initial.length > 0) {\n void this.manager.enableToolsets(initial);\n }\n }\n\n public getMode(): Exclude<Mode, \"ALL\"> {\n return this.mode;\n }\n\n public getManager(): DynamicToolManager {\n return this.manager;\n }\n}\n","export interface ClientResourceCacheOptions {\n maxSize?: number;\n ttlMs?: number; // ms\n pruneIntervalMs?: number;\n}\n\ninterface Entry<T> {\n resource: T;\n lastAccessed: number;\n}\n\nexport class ClientResourceCache<T> {\n private storage = new Map<string, Entry<T>>();\n private maxSize: number;\n private ttlMs: number;\n // Use ReturnType<typeof setInterval> for cross-env typings without NodeJS namespace\n private pruneInterval?: ReturnType<typeof setInterval>;\n\n constructor(options: ClientResourceCacheOptions = {}) {\n this.maxSize = options.maxSize ?? 1000;\n this.ttlMs = options.ttlMs ?? 1000 * 60 * 60;\n const pruneEvery = options.pruneIntervalMs ?? 1000 * 60 * 10;\n this.pruneInterval = setInterval(() => this.pruneExpired(), pruneEvery);\n }\n\n public getEntryCount(): number {\n return this.storage.size;\n }\n\n public getMaxSize(): number {\n return this.maxSize;\n }\n\n public getTtl(): number {\n return this.ttlMs;\n }\n\n public get(key: string): T | null {\n const entry = this.storage.get(key);\n if (!entry) return null;\n if (Date.now() - entry.lastAccessed > this.ttlMs) {\n this.delete(key);\n return null;\n }\n entry.lastAccessed = Date.now();\n this.storage.delete(key);\n this.storage.set(key, entry);\n return entry.resource;\n }\n\n public set(key: string, resource: T): void {\n if (this.storage.size >= this.maxSize) {\n this.evictLeastRecentlyUsed();\n }\n const newEntry: Entry<T> = { resource, lastAccessed: Date.now() };\n this.storage.set(key, newEntry);\n }\n\n public delete(key: string): void {\n this.storage.delete(key);\n }\n\n public stop(): void {\n if (this.pruneInterval) {\n clearInterval(this.pruneInterval);\n this.pruneInterval = undefined;\n }\n }\n\n private evictLeastRecentlyUsed(): void {\n const lruKey = this.storage.keys().next().value as string | undefined;\n if (lruKey) {\n this.delete(lruKey);\n }\n }\n\n private pruneExpired(): void {\n const now = Date.now();\n for (const [key, entry] of this.storage.entries()) {\n if (now - entry.lastAccessed > this.ttlMs) {\n this.delete(key);\n }\n }\n }\n}\n","import Fastify, {\n type FastifyInstance,\n type FastifyReply,\n type FastifyRequest,\n} from \"fastify\";\nimport cors from \"@fastify/cors\";\nimport { randomUUID } from \"node:crypto\";\nimport type { DynamicToolManager } from \"../core/DynamicToolManager.js\";\nimport type { ServerOrchestrator } from \"../core/ServerOrchestrator.js\";\nimport { ClientResourceCache } from \"../session/ClientResourceCache.js\";\nimport { StreamableHTTPServerTransport } from \"@modelcontextprotocol/sdk/server/streamableHttp.js\";\nimport { isInitializeRequest } from \"@modelcontextprotocol/sdk/types.js\";\nimport type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\n\nexport interface FastifyTransportOptions {\n host?: string;\n port?: number;\n basePath?: string; // e.g. \"/\" or \"/api\"\n cors?: boolean;\n logger?: boolean;\n // Optional DI: provide a Fastify instance (e.g., for tests). If provided, start() will not listen.\n app?: FastifyInstance;\n}\n\nexport class FastifyTransport {\n private readonly options: {\n host: string;\n port: number;\n basePath: string;\n cors: boolean;\n logger: boolean;\n app?: FastifyInstance;\n };\n private readonly defaultManager: DynamicToolManager;\n private readonly createBundle: () => {\n server: McpServer;\n orchestrator: ServerOrchestrator;\n };\n private app: FastifyInstance | null = null;\n private readonly configSchema?: object;\n\n // Per-client server bundles and per-client session transports\n private readonly clientCache = new ClientResourceCache<{\n server: McpServer;\n orchestrator: ServerOrchestrator;\n sessions: Map<string, StreamableHTTPServerTransport>;\n }>();\n\n constructor(\n defaultManager: DynamicToolManager,\n createBundle: () => { server: McpServer; orchestrator: ServerOrchestrator },\n options: FastifyTransportOptions = {},\n configSchema?: object\n ) {\n this.defaultManager = defaultManager;\n this.createBundle = createBundle;\n this.options = {\n host: options.host ?? \"0.0.0.0\",\n port: options.port ?? 3000,\n basePath: options.basePath ?? \"/\",\n cors: options.cors ?? true,\n logger: options.logger ?? false,\n app: options.app,\n };\n this.configSchema = configSchema;\n }\n\n public async start(): Promise<void> {\n if (this.app) return;\n const app = this.options.app ?? Fastify({ logger: this.options.logger });\n if (this.options.cors) {\n await app.register(cors, { origin: true });\n }\n\n const base = this.options.basePath.endsWith(\"/\")\n ? this.options.basePath.slice(0, -1)\n : this.options.basePath;\n\n app.get(`${base}/healthz`, async () => ({ ok: true }));\n\n app.get(`${base}/tools`, async () => this.defaultManager.getStatus());\n\n // Config discovery (placeholder schema)\n app.get(`${base}/.well-known/mcp-config`, async (_req, reply) => {\n reply.header(\"Content-Type\", \"application/schema+json; charset=utf-8\");\n const baseSchema = this.configSchema ?? {\n $schema: \"https://json-schema.org/draft/2020-12/schema\",\n title: \"MCP Session Configuration\",\n description: \"Schema for the /mcp endpoint configuration\",\n type: \"object\",\n properties: {},\n required: [],\n \"x-mcp-version\": \"1.0\",\n \"x-query-style\": \"dot+bracket\",\n };\n return baseSchema;\n });\n\n // POST /mcp - JSON-RPC\n app.post(\n `${base}/mcp`,\n async (req: FastifyRequest, reply: FastifyReply) => {\n const clientIdHeader = (\n req.headers[\"mcp-client-id\"] as string | undefined\n )?.trim();\n const clientId =\n clientIdHeader && clientIdHeader.length > 0\n ? clientIdHeader\n : `anon-${randomUUID()}`;\n\n // When anon id, avoid caching (one-off)\n const useCache = !clientId.startsWith(\"anon-\");\n\n let bundle = useCache ? this.clientCache.get(clientId) : null;\n if (!bundle) {\n const created = this.createBundle();\n bundle = {\n server: created.server,\n orchestrator: created.orchestrator,\n sessions: new Map(),\n };\n if (useCache) this.clientCache.set(clientId, bundle);\n }\n\n const sessionId = req.headers[\"mcp-session-id\"] as string | undefined;\n\n let transport: StreamableHTTPServerTransport | undefined;\n if (sessionId && bundle.sessions.get(sessionId)) {\n transport = bundle.sessions.get(sessionId)!;\n } else if (!sessionId && isInitializeRequest((req as any).body)) {\n const newSessionId = randomUUID();\n transport = new StreamableHTTPServerTransport({\n sessionIdGenerator: () => newSessionId,\n onsessioninitialized: (sid: string) => {\n bundle!.sessions.set(sid, transport!);\n },\n });\n try {\n await bundle.server.connect(transport);\n } catch (error) {\n reply.code(500);\n return {\n jsonrpc: \"2.0\",\n error: { code: -32603, message: \"Error initializing server.\" },\n id: null,\n };\n }\n transport.onclose = () => {\n if (transport?.sessionId)\n bundle!.sessions.delete(transport.sessionId);\n };\n } else {\n reply.code(400);\n return {\n jsonrpc: \"2.0\",\n error: { code: -32000, message: \"Session not found or expired\" },\n id: null,\n };\n }\n\n // Delegate handling to SDK transport using raw Node req/res\n await transport.handleRequest(\n (req as any).raw,\n (reply as any).raw,\n (req as any).body\n );\n // Fastify will consider the response already sent by transport\n return reply;\n }\n );\n\n // GET /mcp - SSE notifications\n app.get(`${base}/mcp`, async (req: FastifyRequest, reply: FastifyReply) => {\n const clientIdHeader = (\n req.headers[\"mcp-client-id\"] as string | undefined\n )?.trim();\n const clientId =\n clientIdHeader && clientIdHeader.length > 0 ? clientIdHeader : \"\";\n if (!clientId) {\n reply.code(400);\n return \"Missing mcp-client-id\";\n }\n const bundle = this.clientCache.get(clientId);\n if (!bundle) {\n reply.code(400);\n return \"Invalid or expired client\";\n }\n const sessionId = req.headers[\"mcp-session-id\"] as string | undefined;\n if (!sessionId) {\n reply.code(400);\n return \"Missing mcp-session-id\";\n }\n const transport = bundle.sessions.get(sessionId);\n if (!transport) {\n reply.code(400);\n return \"Invalid or expired session ID\";\n }\n await transport.handleRequest((req as any).raw, (reply as any).raw);\n return reply;\n });\n\n // DELETE /mcp - terminate session\n app.delete(\n `${base}/mcp`,\n async (req: FastifyRequest, reply: FastifyReply) => {\n const clientIdHeader = (\n req.headers[\"mcp-client-id\"] as string | undefined\n )?.trim();\n const clientId =\n clientIdHeader && clientIdHeader.length > 0 ? clientIdHeader : \"\";\n const sessionId = req.headers[\"mcp-session-id\"] as string | undefined;\n if (!clientId || !sessionId) {\n reply.code(400);\n return {\n jsonrpc: \"2.0\",\n error: {\n code: -32600,\n message: \"Missing mcp-client-id or mcp-session-id header\",\n },\n id: null,\n };\n }\n const bundle = this.clientCache.get(clientId);\n const transport = bundle?.sessions.get(sessionId);\n if (!bundle || !transport) {\n reply.code(404);\n return {\n jsonrpc: \"2.0\",\n error: { code: -32000, message: \"Session not found or expired\" },\n id: null,\n };\n }\n reply.code(204).send();\n return reply;\n }\n );\n\n // Only listen if we created the app\n if (!this.options.app) {\n await app.listen({ host: this.options.host, port: this.options.port });\n }\n this.app = app;\n }\n\n public async stop(): Promise<void> {\n if (!this.app) return;\n if (!this.options.app) {\n await this.app.close();\n }\n this.app = null;\n }\n}\n","import { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport type { ExposurePolicy, Mode, ToolSetCatalog } from \"../types/index.js\";\nimport { ServerOrchestrator } from \"../core/ServerOrchestrator.js\";\nimport {\n FastifyTransport,\n type FastifyTransportOptions,\n} from \"../http/FastifyTransport.js\";\n\nexport interface CreateMcpServerOptions {\n catalog: ToolSetCatalog;\n moduleLoaders?: Record<string, any>;\n exposurePolicy?: ExposurePolicy;\n context?: unknown;\n startup?: { mode?: Exclude<Mode, \"ALL\">; toolsets?: string[] | \"ALL\" };\n registerMetaTools?: boolean;\n http?: FastifyTransportOptions;\n mcp?: {\n name?: string;\n version?: string;\n capabilities?: Record<string, unknown>;\n };\n configSchema?: object;\n}\n\nexport async function createMcpServer(options: CreateMcpServerOptions) {\n const mode: Exclude<Mode, \"ALL\"> = options.startup?.mode ?? \"DYNAMIC\";\n const name = options.mcp?.name ?? \"mcp-dynamic-tooling\";\n const version = options.mcp?.version ?? \"0.0.0\";\n const baseCaps = options.mcp?.capabilities ?? {};\n const mergedCaps = {\n ...baseCaps,\n tools: {\n ...(typeof (baseCaps as any).tools === \"object\"\n ? (baseCaps as any).tools\n : {}),\n // listChanged is internal-only and computed by mode\n listChanged: mode === \"DYNAMIC\",\n },\n } as any;\n const server = new McpServer({\n name,\n version,\n capabilities: mergedCaps,\n });\n\n // Typed, guarded notifier\n type NotifierA = {\n server: { notification: (msg: { method: string }) => Promise<void> | void };\n };\n type NotifierB = { notifyToolsListChanged: () => Promise<void> | void };\n const hasNotifierA = (s: unknown): s is NotifierA =>\n typeof (s as any)?.server?.notification === \"function\";\n const hasNotifierB = (s: unknown): s is NotifierB =>\n typeof (s as any)?.notifyToolsListChanged === \"function\";\n const notifyToolsChanged = async (target: unknown) => {\n try {\n if (hasNotifierA(target)) {\n await target.server.notification({\n method: \"notifications/tools/list_changed\",\n });\n return;\n }\n if (hasNotifierB(target)) {\n await target.notifyToolsListChanged();\n }\n } catch {}\n };\n\n const orchestrator = new ServerOrchestrator({\n server,\n catalog: options.catalog,\n moduleLoaders: options.moduleLoaders,\n exposurePolicy: options.exposurePolicy,\n context: options.context,\n notifyToolsListChanged: async () => notifyToolsChanged(server),\n startup: options.startup,\n registerMetaTools:\n options.registerMetaTools !== undefined\n ? options.registerMetaTools\n : mode === \"DYNAMIC\",\n });\n\n const transport = new FastifyTransport(\n orchestrator.getManager(),\n () => {\n // Create a fresh server + orchestrator bundle for a new client when needed\n const innerMode: Exclude<Mode, \"ALL\"> =\n options.startup?.mode ?? \"DYNAMIC\";\n const innerName = options.mcp?.name ?? name;\n const innerVersion = options.mcp?.version ?? version;\n const innerBaseCaps = options.mcp?.capabilities ?? baseCaps;\n const innerMergedCaps = {\n ...innerBaseCaps,\n tools: {\n ...(typeof (innerBaseCaps as any).tools === \"object\"\n ? (innerBaseCaps as any).tools\n : {}),\n listChanged: innerMode === \"DYNAMIC\",\n },\n } as any;\n const server = new McpServer({\n name: innerName,\n version: innerVersion,\n capabilities: innerMergedCaps,\n });\n const orchestrator = new ServerOrchestrator({\n server,\n catalog: options.catalog,\n moduleLoaders: options.moduleLoaders,\n exposurePolicy: options.exposurePolicy,\n context: options.context,\n notifyToolsListChanged: async () => notifyToolsChanged(server),\n startup: options.startup,\n registerMetaTools:\n options.registerMetaTools !== undefined\n ? options.registerMetaTools\n : innerMode === \"DYNAMIC\",\n });\n return { server, orchestrator };\n },\n options.http,\n options.configSchema\n );\n\n return {\n server,\n start: async () => {\n await transport.start();\n },\n close: async () => {\n await transport.stop();\n },\n };\n}\n"],"names":["DEFAULT_KEYS","ModeResolver","options","env","args","input","catalog","raw","s","valid","result","name","toolsets","modules","def","m","sanitized","toolsetNames","error","source","key","value","ModuleResolver","context","collected","modKey","loader","loaded","err","ToolingError","message","code","details","_options","ToolRegistry","toolsetKey","toolName","set","tools","safe","k","v","DynamicToolManager","toolsetName","validation","resolvedTools","mapped","activeToolsets","results","res","successAll","r","tool","all","registerMetaTools","server","manager","mode","z","available","byToolset","items","payload","status","ServerOrchestrator","startup","toolRegistry","initial","ClientResourceCache","pruneEvery","entry","resource","newEntry","lruKey","now","FastifyTransport","defaultManager","createBundle","configSchema","app","Fastify","cors","base","_req","reply","req","clientIdHeader","clientId","randomUUID","useCache","bundle","created","sessionId","transport","isInitializeRequest","newSessionId","StreamableHTTPServerTransport","sid","createMcpServer","version","baseCaps","mergedCaps","McpServer","hasNotifierA","hasNotifierB","notifyToolsChanged","target","orchestrator","innerMode","innerName","innerVersion","innerBaseCaps","innerMergedCaps"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/mode/ModeResolver.ts","../src/mode/ModuleResolver.ts","../src/errors/ToolingError.ts","../src/core/ToolRegistry.ts","../src/core/DynamicToolManager.ts","../src/meta/registerMetaTools.ts","../src/core/ServerOrchestrator.ts","../src/session/ClientResourceCache.ts","../src/http/FastifyTransport.ts","../src/server/createMcpServer.ts"],"sourcesContent":["import type { Mode, ToolSetCatalog } from \"../types/index.js\";\n\ninterface ModeResolverKeys {\n dynamic?: string[]; // keys that, when present/true, enable dynamic mode\n toolsets?: string[]; // keys that carry comma-separated toolsets\n}\n\ninterface ModeResolverOptions {\n keys?: ModeResolverKeys;\n}\n\nconst DEFAULT_KEYS: Required<ModeResolverKeys> = {\n dynamic: [\n \"dynamic-tool-discovery\",\n \"dynamicToolDiscovery\",\n \"DYNAMIC_TOOL_DISCOVERY\",\n ],\n toolsets: [\"tool-sets\", \"toolSets\", \"FMP_TOOL_SETS\"],\n};\n\nexport class ToolsetValidator {\n private readonly keys: Required<ModeResolverKeys>;\n\n constructor(options: ModeResolverOptions = {}) {\n this.keys = {\n dynamic: options.keys?.dynamic ?? DEFAULT_KEYS.dynamic,\n toolsets: options.keys?.toolsets ?? DEFAULT_KEYS.toolsets,\n };\n }\n\n public resolveMode(\n env?: Record<string, string | undefined>,\n args?: Record<string, unknown>\n ): Mode | null {\n // Check args first\n if (this.isDynamicEnabled(args)) return \"DYNAMIC\";\n\n const toolsetsFromArgs = this.getToolsetsString(args);\n if (toolsetsFromArgs) return \"STATIC\";\n\n // Check env next\n if (this.isDynamicEnabled(env)) return \"DYNAMIC\";\n\n const toolsetsFromEnv = this.getToolsetsString(env);\n if (toolsetsFromEnv) return \"STATIC\";\n\n return null; // no override\n }\n\n public parseCommaSeparatedToolSets(\n input: string,\n catalog: ToolSetCatalog\n ): string[] {\n if (!input || typeof input !== \"string\") return [];\n const raw = input\n .split(\",\")\n .map((s) => s.trim())\n .filter((s) => s.length > 0);\n\n const valid = new Set(Object.keys(catalog));\n const result: string[] = [];\n for (const name of raw) {\n if (valid.has(name)) result.push(name);\n else\n console.warn(\n `Invalid toolset '${name}' ignored. Available: ${Array.from(\n valid\n ).join(\", \")}`\n );\n }\n return result;\n }\n\n public getModulesForToolSets(\n toolsets: string[],\n catalog: ToolSetCatalog\n ): string[] {\n const modules = new Set<string>();\n for (const name of toolsets) {\n const def = catalog[name];\n if (!def) continue;\n (def.modules || []).forEach((m) => modules.add(m));\n }\n return Array.from(modules);\n }\n\n public validateToolsetName(\n name: unknown,\n catalog: ToolSetCatalog\n ): { isValid: boolean; sanitized?: string; error?: string } {\n if (!name || typeof name !== \"string\") {\n return {\n isValid: false,\n error: `Invalid toolset name provided. Must be a non-empty string. Available toolsets: ${Object.keys(\n catalog\n ).join(\", \")}`,\n };\n }\n const sanitized = name.trim();\n if (sanitized.length === 0) {\n return {\n isValid: false,\n error: `Empty toolset name provided. Available toolsets: ${Object.keys(\n catalog\n ).join(\", \")}`,\n };\n }\n if (!catalog[sanitized]) {\n return {\n isValid: false,\n error: `Toolset '${sanitized}' not found. Available toolsets: ${Object.keys(\n catalog\n ).join(\", \")}`,\n };\n }\n return { isValid: true, sanitized };\n }\n\n public validateToolsetModules(\n toolsetNames: string[],\n catalog: ToolSetCatalog\n ): { isValid: boolean; modules?: string[]; error?: string } {\n try {\n const modules = this.getModulesForToolSets(toolsetNames, catalog);\n if (!modules || modules.length === 0) {\n return {\n isValid: false,\n error: `No modules found for toolsets: ${toolsetNames.join(\", \")}`,\n };\n }\n return { isValid: true, modules };\n } catch (error) {\n return {\n isValid: false,\n error: `Error resolving modules for ${toolsetNames.join(\", \")}: ${\n error instanceof Error ? error.message : \"Unknown error\"\n }`,\n };\n }\n }\n\n private isDynamicEnabled(\n source?: Record<string, unknown> | Record<string, string | undefined>\n ): boolean {\n if (!source) return false;\n for (const key of this.keys.dynamic) {\n const value = (source as any)[key];\n if (value === true) return true;\n if (typeof value === \"string\") {\n const v = value.trim().toLowerCase();\n if (v === \"true\") return true;\n }\n }\n return false;\n }\n\n private getToolsetsString(\n source?: Record<string, unknown> | Record<string, string | undefined>\n ): string | undefined {\n if (!source) return undefined;\n for (const key of this.keys.toolsets) {\n const value = (source as any)[key];\n if (typeof value === \"string\" && value.trim().length > 0)\n return value as string;\n }\n return undefined;\n }\n}\n","import type {\n ToolSetCatalog,\n ToolSetDefinition,\n McpToolDefinition,\n ModuleLoader,\n} from \"../types/index.js\";\n\nexport interface ModuleResolverOptions {\n catalog: ToolSetCatalog;\n moduleLoaders?: Record<string, ModuleLoader>;\n}\n\nexport class ModuleResolver {\n private readonly catalog: ToolSetCatalog;\n private readonly moduleLoaders: Record<string, ModuleLoader>;\n\n constructor(options: ModuleResolverOptions) {\n this.catalog = options.catalog;\n this.moduleLoaders = options.moduleLoaders ?? {};\n }\n\n public getAvailableToolsets(): string[] {\n return Object.keys(this.catalog);\n }\n\n public getToolsetDefinition(name: string): ToolSetDefinition | undefined {\n return this.catalog[name];\n }\n\n public validateToolsetName(name: unknown): {\n isValid: boolean;\n sanitized?: string;\n error?: string;\n } {\n if (!name || typeof name !== \"string\") {\n return {\n isValid: false,\n error: `Invalid toolset name provided. Must be a non-empty string. Available toolsets: ${this.getAvailableToolsets().join(\n \", \"\n )}`,\n };\n }\n const sanitized = name.trim();\n if (sanitized.length === 0) {\n return {\n isValid: false,\n error: `Empty toolset name provided. Available toolsets: ${this.getAvailableToolsets().join(\n \", \"\n )}`,\n };\n }\n if (!this.catalog[sanitized]) {\n return {\n isValid: false,\n error: `Toolset '${sanitized}' not found. Available toolsets: ${this.getAvailableToolsets().join(\n \", \"\n )}`,\n };\n }\n return { isValid: true, sanitized };\n }\n\n public async resolveToolsForToolsets(\n toolsets: string[],\n context?: unknown\n ): Promise<McpToolDefinition[]> {\n const collected: McpToolDefinition[] = [];\n for (const name of toolsets) {\n const def = this.catalog[name];\n if (!def) continue;\n if (Array.isArray(def.tools) && def.tools.length > 0) {\n collected.push(...def.tools);\n }\n if (Array.isArray(def.modules) && def.modules.length > 0) {\n for (const modKey of def.modules) {\n const loader = this.moduleLoaders[modKey];\n if (!loader) continue;\n try {\n const loaded = await loader(context);\n if (Array.isArray(loaded) && loaded.length > 0) {\n collected.push(...loaded);\n }\n } catch (err) {\n console.warn(\n `Module loader '${modKey}' failed for toolset '${name}':`,\n err\n );\n }\n }\n }\n }\n return collected;\n }\n}\n","import type { ToolingErrorCode } from \"../types/index.js\";\n\nexport class ToolingError extends Error {\n public readonly code: ToolingErrorCode;\n public readonly details?: Record<string, unknown>;\n\n constructor(\n message: string,\n code: ToolingErrorCode,\n details?: Record<string, unknown>,\n _options?: unknown\n ) {\n super(message);\n this.name = \"ToolingError\";\n this.code = code;\n this.details = details;\n }\n}\n","import type { McpToolDefinition } from \"../types/index.js\";\nimport { ToolingError } from \"../errors/ToolingError.js\";\n\nexport interface ToolRegistryOptions {\n namespaceWithToolset?: boolean;\n}\n\nexport class ToolRegistry {\n private readonly options: Required<ToolRegistryOptions>;\n private readonly names = new Set<string>();\n private readonly toolsetToNames = new Map<string, Set<string>>();\n\n constructor(options: ToolRegistryOptions = {}) {\n this.options = {\n namespaceWithToolset: options.namespaceWithToolset ?? true,\n };\n }\n\n public getSafeName(toolsetKey: string, toolName: string): string {\n if (!this.options.namespaceWithToolset) return toolName;\n if (toolName.startsWith(`${toolsetKey}.`)) return toolName;\n return `${toolsetKey}.${toolName}`;\n }\n\n public has(name: string): boolean {\n return this.names.has(name);\n }\n\n public add(name: string): void {\n if (this.names.has(name)) {\n throw new ToolingError(\n `Tool name collision: '${name}' already registered`,\n \"E_TOOL_NAME_CONFLICT\"\n );\n }\n this.names.add(name);\n }\n\n public addForToolset(toolsetKey: string, name: string): void {\n this.add(name);\n const set = this.toolsetToNames.get(toolsetKey) ?? new Set<string>();\n set.add(name);\n this.toolsetToNames.set(toolsetKey, set);\n }\n\n public mapAndValidate(\n toolsetKey: string,\n tools: McpToolDefinition[]\n ): McpToolDefinition[] {\n return tools.map((t) => {\n const safe = this.getSafeName(toolsetKey, t.name);\n if (this.has(safe)) {\n throw new ToolingError(\n `Tool name collision for '${safe}'`,\n \"E_TOOL_NAME_CONFLICT\"\n );\n }\n return { ...t, name: safe };\n });\n }\n\n public list(): string[] {\n return Array.from(this.names);\n }\n\n public listByToolset(): Record<string, string[]> {\n const result: Record<string, string[]> = {};\n for (const [k, v] of this.toolsetToNames.entries()) {\n result[k] = Array.from(v);\n }\n return result;\n }\n}\n","import type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport type {\n ExposurePolicy,\n McpToolDefinition,\n ToolSetDefinition,\n ToolingErrorCode,\n} from \"../types/index.js\";\nimport { ModuleResolver } from \"../mode/ModuleResolver.js\";\nimport { ToolRegistry } from \"./ToolRegistry.js\";\n\nexport interface DynamicToolManagerOptions {\n server: McpServer;\n resolver: ModuleResolver;\n context?: unknown;\n onToolsListChanged?: () => Promise<void> | void;\n exposurePolicy?: ExposurePolicy;\n toolRegistry?: ToolRegistry;\n}\n\nexport class DynamicToolManager {\n private readonly server: McpServer;\n private readonly resolver: ModuleResolver;\n private readonly context?: unknown;\n private readonly onToolsListChanged?: () => Promise<void> | void;\n private readonly exposurePolicy?: ExposurePolicy;\n private readonly toolRegistry: ToolRegistry;\n\n private readonly activeToolsets = new Set<string>();\n\n constructor(options: DynamicToolManagerOptions) {\n this.server = options.server;\n this.resolver = options.resolver;\n this.context = options.context;\n this.onToolsListChanged = options.onToolsListChanged;\n this.exposurePolicy = options.exposurePolicy;\n this.toolRegistry =\n options.toolRegistry ?? new ToolRegistry({ namespaceWithToolset: true });\n }\n\n public getAvailableToolsets(): string[] {\n return this.resolver.getAvailableToolsets();\n }\n\n public getActiveToolsets(): string[] {\n return Array.from(this.activeToolsets);\n }\n\n public getToolsetDefinition(name: string): ToolSetDefinition | undefined {\n return this.resolver.getToolsetDefinition(name);\n }\n\n public isActive(name: string): boolean {\n return this.activeToolsets.has(name);\n }\n\n public async enableToolset(\n toolsetName: string\n ): Promise<{ success: boolean; message: string }> {\n const validation = this.resolver.validateToolsetName(toolsetName);\n if (!validation.isValid || !validation.sanitized) {\n return {\n success: false,\n message: validation.error || \"Unknown validation error\",\n };\n }\n const sanitized = validation.sanitized;\n if (this.activeToolsets.has(sanitized)) {\n return {\n success: false,\n message: `Toolset '${sanitized}' is already enabled.`,\n };\n }\n\n try {\n const resolvedTools = await this.resolver.resolveToolsForToolsets(\n [sanitized],\n this.context\n );\n\n // Exposure policy checks\n if (\n this.exposurePolicy?.allowlist &&\n !this.exposurePolicy.allowlist.includes(sanitized)\n ) {\n return {\n success: false,\n message: `Toolset '${sanitized}' is not allowed by policy.`,\n };\n }\n if (\n this.exposurePolicy?.denylist &&\n this.exposurePolicy.denylist.includes(sanitized)\n ) {\n return {\n success: false,\n message: `Toolset '${sanitized}' is denied by policy.`,\n };\n }\n if (this.exposurePolicy?.maxActiveToolsets !== undefined) {\n const next = this.activeToolsets.size + 1;\n if (next > this.exposurePolicy.maxActiveToolsets) {\n this.exposurePolicy.onLimitExceeded?.(\n [sanitized],\n Array.from(this.activeToolsets)\n );\n return {\n success: false,\n message: `Activation exceeds maxActiveToolsets (${this.exposurePolicy.maxActiveToolsets}).`,\n };\n }\n }\n\n // Register all resolved tools (direct + module-derived)\n if (resolvedTools && resolvedTools.length > 0) {\n const mapped = this.toolRegistry.mapAndValidate(\n sanitized,\n resolvedTools\n );\n this.registerDirectTools(mapped, sanitized);\n }\n\n // Track state (modules no longer tracked)\n this.activeToolsets.add(sanitized);\n\n // Notify list change\n try {\n await this.onToolsListChanged?.();\n } catch (err) {\n console.warn(`Failed to send tool list change notification:`, err);\n }\n\n return {\n success: true,\n message: `Toolset '${sanitized}' enabled successfully. Registered ${\n resolvedTools?.length ?? 0\n } tools.`,\n };\n } catch (error) {\n this.activeToolsets.delete(sanitized);\n return {\n success: false,\n message: `Failed to enable toolset '${sanitized}': ${\n error instanceof Error ? error.message : \"Unknown error\"\n }`,\n };\n }\n }\n\n public async disableToolset(\n toolsetName: string\n ): Promise<{ success: boolean; message: string }> {\n const validation = this.resolver.validateToolsetName(toolsetName);\n if (!validation.isValid || !validation.sanitized) {\n const activeToolsets =\n Array.from(this.activeToolsets).join(\", \") || \"none\";\n const base = validation.error || \"Unknown validation error\";\n return {\n success: false,\n message: `${base} Active toolsets: ${activeToolsets}`,\n };\n }\n const sanitized = validation.sanitized;\n if (!this.activeToolsets.has(sanitized)) {\n return {\n success: false,\n message: `Toolset '${sanitized}' is not currently active. Active toolsets: ${\n Array.from(this.activeToolsets).join(\", \") || \"none\"\n }`,\n };\n }\n\n // State-only disable; no unregistration support in MCP\n this.activeToolsets.delete(sanitized);\n\n try {\n await this.onToolsListChanged?.();\n } catch (err) {\n console.warn(`Failed to send tool list change notification:`, err);\n }\n\n return {\n success: true,\n message: `Toolset '${sanitized}' disabled successfully. Individual tools remain registered due to MCP limitations.`,\n };\n }\n\n public getStatus() {\n return {\n availableToolsets: this.getAvailableToolsets(),\n activeToolsets: this.getActiveToolsets(),\n registeredModules: [],\n totalToolsets: this.getAvailableToolsets().length,\n activeCount: this.activeToolsets.size,\n tools: this.toolRegistry.list(),\n toolsetToTools: this.toolRegistry.listByToolset(),\n };\n }\n\n public async enableToolsets(toolsetNames: string[]): Promise<{\n success: boolean;\n results: Array<{\n name: string;\n success: boolean;\n message: string;\n code?: ToolingErrorCode;\n }>;\n message: string;\n }> {\n const results: Array<{\n name: string;\n success: boolean;\n message: string;\n code?: ToolingErrorCode;\n }> = [];\n for (const name of toolsetNames) {\n try {\n const res = await this.enableToolset(name);\n results.push({ name, ...res });\n } catch (err) {\n results.push({\n name,\n success: false,\n message: err instanceof Error ? err.message : \"Unknown error\",\n code: \"E_INTERNAL\",\n });\n }\n }\n const successAll = results.every((r) => r.success);\n const message = successAll\n ? \"All toolsets enabled\"\n : \"Some toolsets failed to enable\";\n if (results.length > 0) {\n try {\n await this.onToolsListChanged?.();\n } catch {}\n }\n return { success: successAll, results, message };\n }\n\n private registerDirectTools(\n tools: McpToolDefinition[],\n toolsetKey?: string\n ): void {\n for (const tool of tools) {\n try {\n this.server.tool(\n tool.name,\n tool.description,\n tool.inputSchema as any,\n async (args: any) => {\n return await tool.handler(args);\n }\n );\n if (toolsetKey) this.toolRegistry.addForToolset(toolsetKey, tool.name);\n else this.toolRegistry.add(tool.name);\n } catch (err) {\n console.error(`Failed to register direct tool '${tool.name}':`, err);\n throw err;\n }\n }\n }\n\n public async enableAllToolsets(): Promise<{\n success: boolean;\n results: Array<{\n name: string;\n success: boolean;\n message: string;\n code?: ToolingErrorCode;\n }>;\n message: string;\n }> {\n const all = this.getAvailableToolsets();\n return this.enableToolsets(all);\n }\n}\n","import type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport type { Mode } from \"../types/index.js\";\nimport { z } from \"zod\";\nimport { DynamicToolManager } from \"../core/DynamicToolManager.js\";\n\nexport function registerMetaTools(\n server: McpServer,\n manager: DynamicToolManager,\n options?: { mode?: Exclude<Mode, \"ALL\"> }\n): void {\n const mode = options?.mode ?? \"DYNAMIC\";\n // list_tools is always available\n server.tool(\n \"enable_toolset\",\n \"Enable a toolset by name\",\n { name: z.string().describe(\"Toolset name\") },\n async (args: any) => {\n const { name } = args as { name: string };\n const result = await manager.enableToolset(name);\n return {\n content: [{ type: \"text\", text: JSON.stringify(result) }],\n };\n }\n );\n\n server.tool(\n \"disable_toolset\",\n \"Disable a toolset by name (state only)\",\n { name: z.string().describe(\"Toolset name\") },\n async (args: any) => {\n const { name } = args as { name: string };\n const result = await manager.disableToolset(name);\n return {\n content: [{ type: \"text\", text: JSON.stringify(result) }],\n };\n }\n );\n\n if (mode === \"DYNAMIC\") {\n server.tool(\n \"list_toolsets\",\n \"List available toolsets with active status and definitions\",\n {},\n async () => {\n const available = manager.getAvailableToolsets();\n const byToolset = manager.getStatus().toolsetToTools;\n const items = available.map((key) => {\n const def = manager.getToolsetDefinition(key);\n return {\n key,\n active: manager.isActive(key),\n definition: def\n ? {\n name: def.name,\n description: def.description,\n modules: def.modules ?? [],\n decisionCriteria: def.decisionCriteria ?? undefined,\n }\n : null,\n tools: byToolset[key] ?? [],\n };\n });\n return {\n content: [\n { type: \"text\", text: JSON.stringify({ toolsets: items }) },\n ],\n };\n }\n );\n\n server.tool(\n \"describe_toolset\",\n \"Describe a toolset with definition, active status and tools\",\n { name: z.string().describe(\"Toolset name\") },\n async (args: any) => {\n const { name } = args as { name: string };\n const def = manager.getToolsetDefinition(name);\n const byToolset = manager.getStatus().toolsetToTools;\n if (!def) {\n return {\n content: [\n {\n type: \"text\",\n text: JSON.stringify({ error: `Unknown toolset '${name}'` }),\n },\n ],\n };\n }\n const payload = {\n key: name,\n active: manager.isActive(name),\n definition: {\n name: def.name,\n description: def.description,\n modules: def.modules ?? [],\n decisionCriteria: def.decisionCriteria ?? undefined,\n },\n tools: byToolset[name] ?? [],\n };\n return {\n content: [{ type: \"text\", text: JSON.stringify(payload) }],\n };\n }\n );\n }\n\n server.tool(\n \"list_tools\",\n \"List currently registered tool names (best effort)\",\n {},\n async () => {\n const status = manager.getStatus();\n const payload = {\n tools: status.tools,\n toolsetToTools: status.toolsetToTools,\n };\n return {\n content: [{ type: \"text\", text: JSON.stringify(payload) }],\n };\n }\n );\n}\n","import type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { ToolsetValidator } from \"../mode/ToolsetValidator.js\";\nimport { ModuleResolver } from \"../mode/ModuleResolver.js\";\nimport { DynamicToolManager } from \"./DynamicToolManager.js\";\nimport { registerMetaTools } from \"../meta/registerMetaTools.js\";\nimport type { ExposurePolicy, Mode, ToolSetCatalog } from \"../types/index.js\";\nimport { ToolRegistry } from \"./ToolRegistry.js\";\n\nexport interface ServerOrchestratorOptions {\n server: McpServer;\n catalog: ToolSetCatalog;\n moduleLoaders?: Record<string, any>;\n exposurePolicy?: ExposurePolicy;\n context?: unknown;\n notifyToolsListChanged?: () => Promise<void> | void;\n startup?: { mode?: Exclude<Mode, \"ALL\">; toolsets?: string[] | \"ALL\" };\n registerMetaTools?: boolean;\n}\n\nexport class ServerOrchestrator {\n private readonly mode: Exclude<Mode, \"ALL\">;\n private readonly resolver: ModuleResolver;\n private readonly manager: DynamicToolManager;\n private readonly toolsetValidator: ToolsetValidator;\n\n constructor(options: ServerOrchestratorOptions) {\n this.toolsetValidator = new ToolsetValidator();\n const startup = options.startup ?? {};\n const resolved = this.resolveStartupConfig(startup, options.catalog);\n this.mode = resolved.mode;\n this.resolver = new ModuleResolver({\n catalog: options.catalog,\n moduleLoaders: options.moduleLoaders,\n });\n const toolRegistry = new ToolRegistry({\n namespaceWithToolset:\n options.exposurePolicy?.namespaceToolsWithSetKey ?? true,\n });\n this.manager = new DynamicToolManager({\n server: options.server,\n resolver: this.resolver,\n context: options.context,\n onToolsListChanged: options.notifyToolsListChanged,\n exposurePolicy: options.exposurePolicy,\n toolRegistry,\n });\n\n // Register meta-tools only if requested (default true)\n if (options.registerMetaTools !== false) {\n registerMetaTools(options.server, this.manager, { mode: this.mode });\n }\n\n // Startup behavior\n const initial = resolved.toolsets;\n if (initial === \"ALL\") {\n void this.manager.enableToolsets(this.resolver.getAvailableToolsets());\n } else if (Array.isArray(initial) && initial.length > 0) {\n void this.manager.enableToolsets(initial);\n }\n }\n\n private resolveStartupConfig(\n startup: { mode?: Exclude<Mode, \"ALL\">; toolsets?: string[] | \"ALL\" },\n catalog: ToolSetCatalog\n ): { mode: Exclude<Mode, \"ALL\">; toolsets?: string[] | \"ALL\" } {\n // Explicit mode dominates\n if (startup.mode) {\n if (startup.mode === \"DYNAMIC\" && startup.toolsets) {\n console.warn(\"startup.toolsets provided but ignored in DYNAMIC mode\");\n return { mode: \"DYNAMIC\" };\n }\n if (startup.mode === \"STATIC\") {\n if (startup.toolsets === \"ALL\")\n return { mode: \"STATIC\", toolsets: \"ALL\" };\n const names = Array.isArray(startup.toolsets) ? startup.toolsets : [];\n const valid: string[] = [];\n for (const name of names) {\n const { isValid, sanitized, error } =\n this.toolsetValidator.validateToolsetName(name, catalog);\n if (isValid && sanitized) valid.push(sanitized);\n else if (error) console.warn(error);\n }\n if (names.length > 0 && valid.length === 0) {\n throw new Error(\n \"STATIC mode requires valid toolsets or 'ALL'; none were valid\"\n );\n }\n return { mode: \"STATIC\", toolsets: valid };\n }\n return { mode: startup.mode };\n }\n\n // No explicit mode; infer from toolsets\n if (startup.toolsets === \"ALL\") return { mode: \"STATIC\", toolsets: \"ALL\" };\n if (Array.isArray(startup.toolsets) && startup.toolsets.length > 0) {\n const valid: string[] = [];\n for (const name of startup.toolsets) {\n const { isValid, sanitized, error } =\n this.toolsetValidator.validateToolsetName(name, catalog);\n if (isValid && sanitized) valid.push(sanitized);\n else if (error) console.warn(error);\n }\n if (valid.length === 0) {\n throw new Error(\n \"STATIC mode requires valid toolsets or 'ALL'; none were valid\"\n );\n }\n return { mode: \"STATIC\", toolsets: valid };\n }\n\n // Default\n return { mode: \"DYNAMIC\" };\n }\n\n public getMode(): Exclude<Mode, \"ALL\"> {\n return this.mode;\n }\n\n public getManager(): DynamicToolManager {\n return this.manager;\n }\n}\n","export interface ClientResourceCacheOptions {\n maxSize?: number;\n ttlMs?: number; // ms\n pruneIntervalMs?: number;\n}\n\ninterface Entry<T> {\n resource: T;\n lastAccessed: number;\n}\n\nexport class ClientResourceCache<T> {\n private storage = new Map<string, Entry<T>>();\n private maxSize: number;\n private ttlMs: number;\n // Use ReturnType<typeof setInterval> for cross-env typings without NodeJS namespace\n private pruneInterval?: ReturnType<typeof setInterval>;\n\n constructor(options: ClientResourceCacheOptions = {}) {\n this.maxSize = options.maxSize ?? 1000;\n this.ttlMs = options.ttlMs ?? 1000 * 60 * 60;\n const pruneEvery = options.pruneIntervalMs ?? 1000 * 60 * 10;\n this.pruneInterval = setInterval(() => this.pruneExpired(), pruneEvery);\n }\n\n public getEntryCount(): number {\n return this.storage.size;\n }\n\n public getMaxSize(): number {\n return this.maxSize;\n }\n\n public getTtl(): number {\n return this.ttlMs;\n }\n\n public get(key: string): T | null {\n const entry = this.storage.get(key);\n if (!entry) return null;\n if (Date.now() - entry.lastAccessed > this.ttlMs) {\n this.delete(key);\n return null;\n }\n entry.lastAccessed = Date.now();\n this.storage.delete(key);\n this.storage.set(key, entry);\n return entry.resource;\n }\n\n public set(key: string, resource: T): void {\n if (this.storage.size >= this.maxSize) {\n this.evictLeastRecentlyUsed();\n }\n const newEntry: Entry<T> = { resource, lastAccessed: Date.now() };\n this.storage.set(key, newEntry);\n }\n\n public delete(key: string): void {\n this.storage.delete(key);\n }\n\n public stop(): void {\n if (this.pruneInterval) {\n clearInterval(this.pruneInterval);\n this.pruneInterval = undefined;\n }\n }\n\n private evictLeastRecentlyUsed(): void {\n const lruKey = this.storage.keys().next().value as string | undefined;\n if (lruKey) {\n this.delete(lruKey);\n }\n }\n\n private pruneExpired(): void {\n const now = Date.now();\n for (const [key, entry] of this.storage.entries()) {\n if (now - entry.lastAccessed > this.ttlMs) {\n this.delete(key);\n }\n }\n }\n}\n","import Fastify, {\n type FastifyInstance,\n type FastifyReply,\n type FastifyRequest,\n} from \"fastify\";\nimport cors from \"@fastify/cors\";\nimport { randomUUID } from \"node:crypto\";\nimport type { DynamicToolManager } from \"../core/DynamicToolManager.js\";\nimport type { ServerOrchestrator } from \"../core/ServerOrchestrator.js\";\nimport { ClientResourceCache } from \"../session/ClientResourceCache.js\";\nimport { StreamableHTTPServerTransport } from \"@modelcontextprotocol/sdk/server/streamableHttp.js\";\nimport { isInitializeRequest } from \"@modelcontextprotocol/sdk/types.js\";\nimport type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\n\nexport interface FastifyTransportOptions {\n host?: string;\n port?: number;\n basePath?: string; // e.g. \"/\" or \"/api\"\n cors?: boolean;\n logger?: boolean;\n // Optional DI: provide a Fastify instance (e.g., for tests). If provided, start() will not listen.\n app?: FastifyInstance;\n}\n\nexport class FastifyTransport {\n private readonly options: {\n host: string;\n port: number;\n basePath: string;\n cors: boolean;\n logger: boolean;\n app?: FastifyInstance;\n };\n private readonly defaultManager: DynamicToolManager;\n private readonly createBundle: () => {\n server: McpServer;\n orchestrator: ServerOrchestrator;\n };\n private app: FastifyInstance | null = null;\n private readonly configSchema?: object;\n\n // Per-client server bundles and per-client session transports\n private readonly clientCache = new ClientResourceCache<{\n server: McpServer;\n orchestrator: ServerOrchestrator;\n sessions: Map<string, StreamableHTTPServerTransport>;\n }>();\n\n constructor(\n defaultManager: DynamicToolManager,\n createBundle: () => { server: McpServer; orchestrator: ServerOrchestrator },\n options: FastifyTransportOptions = {},\n configSchema?: object\n ) {\n this.defaultManager = defaultManager;\n this.createBundle = createBundle;\n this.options = {\n host: options.host ?? \"0.0.0.0\",\n port: options.port ?? 3000,\n basePath: options.basePath ?? \"/\",\n cors: options.cors ?? true,\n logger: options.logger ?? false,\n app: options.app,\n };\n this.configSchema = configSchema;\n }\n\n public async start(): Promise<void> {\n if (this.app) return;\n const app = this.options.app ?? Fastify({ logger: this.options.logger });\n if (this.options.cors) {\n await app.register(cors, { origin: true });\n }\n\n const base = this.options.basePath.endsWith(\"/\")\n ? this.options.basePath.slice(0, -1)\n : this.options.basePath;\n\n app.get(`${base}/healthz`, async () => ({ ok: true }));\n\n app.get(`${base}/tools`, async () => this.defaultManager.getStatus());\n\n // Config discovery (placeholder schema)\n app.get(`${base}/.well-known/mcp-config`, async (_req, reply) => {\n reply.header(\"Content-Type\", \"application/schema+json; charset=utf-8\");\n const baseSchema = this.configSchema ?? {\n $schema: \"https://json-schema.org/draft/2020-12/schema\",\n title: \"MCP Session Configuration\",\n description: \"Schema for the /mcp endpoint configuration\",\n type: \"object\",\n properties: {},\n required: [],\n \"x-mcp-version\": \"1.0\",\n \"x-query-style\": \"dot+bracket\",\n };\n return baseSchema;\n });\n\n // POST /mcp - JSON-RPC\n app.post(\n `${base}/mcp`,\n async (req: FastifyRequest, reply: FastifyReply) => {\n const clientIdHeader = (\n req.headers[\"mcp-client-id\"] as string | undefined\n )?.trim();\n const clientId =\n clientIdHeader && clientIdHeader.length > 0\n ? clientIdHeader\n : `anon-${randomUUID()}`;\n\n // When anon id, avoid caching (one-off)\n const useCache = !clientId.startsWith(\"anon-\");\n\n let bundle = useCache ? this.clientCache.get(clientId) : null;\n if (!bundle) {\n const created = this.createBundle();\n bundle = {\n server: created.server,\n orchestrator: created.orchestrator,\n sessions: new Map(),\n };\n if (useCache) this.clientCache.set(clientId, bundle);\n }\n\n const sessionId = req.headers[\"mcp-session-id\"] as string | undefined;\n\n let transport: StreamableHTTPServerTransport | undefined;\n if (sessionId && bundle.sessions.get(sessionId)) {\n transport = bundle.sessions.get(sessionId)!;\n } else if (!sessionId && isInitializeRequest((req as any).body)) {\n const newSessionId = randomUUID();\n transport = new StreamableHTTPServerTransport({\n sessionIdGenerator: () => newSessionId,\n onsessioninitialized: (sid: string) => {\n bundle!.sessions.set(sid, transport!);\n },\n });\n try {\n await bundle.server.connect(transport);\n } catch (error) {\n reply.code(500);\n return {\n jsonrpc: \"2.0\",\n error: { code: -32603, message: \"Error initializing server.\" },\n id: null,\n };\n }\n transport.onclose = () => {\n if (transport?.sessionId)\n bundle!.sessions.delete(transport.sessionId);\n };\n } else {\n reply.code(400);\n return {\n jsonrpc: \"2.0\",\n error: { code: -32000, message: \"Session not found or expired\" },\n id: null,\n };\n }\n\n // Delegate handling to SDK transport using raw Node req/res\n await transport.handleRequest(\n (req as any).raw,\n (reply as any).raw,\n (req as any).body\n );\n // Fastify will consider the response already sent by transport\n return reply;\n }\n );\n\n // GET /mcp - SSE notifications\n app.get(`${base}/mcp`, async (req: FastifyRequest, reply: FastifyReply) => {\n const clientIdHeader = (\n req.headers[\"mcp-client-id\"] as string | undefined\n )?.trim();\n const clientId =\n clientIdHeader && clientIdHeader.length > 0 ? clientIdHeader : \"\";\n if (!clientId) {\n reply.code(400);\n return \"Missing mcp-client-id\";\n }\n const bundle = this.clientCache.get(clientId);\n if (!bundle) {\n reply.code(400);\n return \"Invalid or expired client\";\n }\n const sessionId = req.headers[\"mcp-session-id\"] as string | undefined;\n if (!sessionId) {\n reply.code(400);\n return \"Missing mcp-session-id\";\n }\n const transport = bundle.sessions.get(sessionId);\n if (!transport) {\n reply.code(400);\n return \"Invalid or expired session ID\";\n }\n await transport.handleRequest((req as any).raw, (reply as any).raw);\n return reply;\n });\n\n // DELETE /mcp - terminate session\n app.delete(\n `${base}/mcp`,\n async (req: FastifyRequest, reply: FastifyReply) => {\n const clientIdHeader = (\n req.headers[\"mcp-client-id\"] as string | undefined\n )?.trim();\n const clientId =\n clientIdHeader && clientIdHeader.length > 0 ? clientIdHeader : \"\";\n const sessionId = req.headers[\"mcp-session-id\"] as string | undefined;\n if (!clientId || !sessionId) {\n reply.code(400);\n return {\n jsonrpc: \"2.0\",\n error: {\n code: -32600,\n message: \"Missing mcp-client-id or mcp-session-id header\",\n },\n id: null,\n };\n }\n const bundle = this.clientCache.get(clientId);\n const transport = bundle?.sessions.get(sessionId);\n if (!bundle || !transport) {\n reply.code(404);\n return {\n jsonrpc: \"2.0\",\n error: { code: -32000, message: \"Session not found or expired\" },\n id: null,\n };\n }\n reply.code(204).send();\n return reply;\n }\n );\n\n // Only listen if we created the app\n if (!this.options.app) {\n await app.listen({ host: this.options.host, port: this.options.port });\n }\n this.app = app;\n }\n\n public async stop(): Promise<void> {\n if (!this.app) return;\n if (!this.options.app) {\n await this.app.close();\n }\n this.app = null;\n }\n}\n","import type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport type { ExposurePolicy, Mode, ToolSetCatalog } from \"../types/index.js\";\nimport { ServerOrchestrator } from \"../core/ServerOrchestrator.js\";\nimport {\n FastifyTransport,\n type FastifyTransportOptions,\n} from \"../http/FastifyTransport.js\";\n\nexport interface CreateMcpServerOptions {\n catalog: ToolSetCatalog;\n moduleLoaders?: Record<string, any>;\n exposurePolicy?: ExposurePolicy;\n context?: unknown;\n startup?: { mode?: Exclude<Mode, \"ALL\">; toolsets?: string[] | \"ALL\" };\n registerMetaTools?: boolean;\n http?: FastifyTransportOptions;\n /** Factory to create an MCP server instance. Required.\n * In DYNAMIC mode, a new instance is created per client bundle.\n * In STATIC mode, a single instance is created and reused across bundles.\n */\n createServer: () => McpServer;\n configSchema?: object;\n}\n\nexport async function createMcpServer(options: CreateMcpServerOptions) {\n const mode: Exclude<Mode, \"ALL\"> = options.startup?.mode ?? \"DYNAMIC\";\n if (typeof options.createServer !== \"function\") {\n throw new Error(\"createMcpServer: `createServer` (factory) is required\");\n }\n const baseServer: McpServer = options.createServer();\n\n // Typed, guarded notifier\n type NotifierA = {\n server: { notification: (msg: { method: string }) => Promise<void> | void };\n };\n type NotifierB = { notifyToolsListChanged: () => Promise<void> | void };\n const hasNotifierA = (s: unknown): s is NotifierA =>\n typeof (s as any)?.server?.notification === \"function\";\n const hasNotifierB = (s: unknown): s is NotifierB =>\n typeof (s as any)?.notifyToolsListChanged === \"function\";\n const notifyToolsChanged = async (target: unknown) => {\n try {\n if (hasNotifierA(target)) {\n await target.server.notification({\n method: \"notifications/tools/list_changed\",\n });\n return;\n }\n if (hasNotifierB(target)) {\n await target.notifyToolsListChanged();\n }\n } catch {}\n };\n\n const orchestrator = new ServerOrchestrator({\n server: baseServer,\n catalog: options.catalog,\n moduleLoaders: options.moduleLoaders,\n exposurePolicy: options.exposurePolicy,\n context: options.context,\n notifyToolsListChanged: async () => notifyToolsChanged(baseServer),\n startup: options.startup,\n registerMetaTools:\n options.registerMetaTools !== undefined\n ? options.registerMetaTools\n : mode === \"DYNAMIC\",\n });\n\n const transport = new FastifyTransport(\n orchestrator.getManager(),\n () => {\n // Create a server + orchestrator bundle\n // for a new client when needed\n const createdServer: McpServer =\n mode === \"DYNAMIC\" ? options.createServer() : baseServer;\n const orchestrator = new ServerOrchestrator({\n server: createdServer,\n catalog: options.catalog,\n moduleLoaders: options.moduleLoaders,\n exposurePolicy: options.exposurePolicy,\n context: options.context,\n notifyToolsListChanged: async () => notifyToolsChanged(createdServer),\n startup: options.startup,\n registerMetaTools:\n options.registerMetaTools !== undefined\n ? options.registerMetaTools\n : mode === \"DYNAMIC\",\n });\n return { server: createdServer, orchestrator };\n },\n options.http,\n options.configSchema\n );\n\n return {\n server: baseServer,\n start: async () => {\n await transport.start();\n },\n close: async () => {\n await transport.stop();\n },\n };\n}\n"],"names":["DEFAULT_KEYS","ToolsetValidator","options","env","args","input","catalog","raw","s","valid","result","name","toolsets","modules","def","m","sanitized","toolsetNames","error","source","key","value","ModuleResolver","context","collected","modKey","loader","loaded","err","ToolingError","message","code","details","_options","ToolRegistry","toolsetKey","toolName","set","tools","safe","k","v","DynamicToolManager","toolsetName","validation","resolvedTools","mapped","activeToolsets","results","res","successAll","tool","all","registerMetaTools","server","manager","mode","z","available","byToolset","items","payload","status","ServerOrchestrator","startup","resolved","toolRegistry","initial","names","isValid","ClientResourceCache","pruneEvery","entry","resource","newEntry","lruKey","now","FastifyTransport","defaultManager","createBundle","configSchema","app","Fastify","cors","base","_req","reply","req","clientIdHeader","clientId","randomUUID","useCache","bundle","created","sessionId","transport","isInitializeRequest","newSessionId","StreamableHTTPServerTransport","sid","createMcpServer","baseServer","hasNotifierA","hasNotifierB","notifyToolsChanged","target","orchestrator","createdServer"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "toolception",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -18,6 +18,8 @@
|
|
|
18
18
|
"test": "vitest",
|
|
19
19
|
"test:run": "vitest run",
|
|
20
20
|
"test:coverage": "vitest run --coverage",
|
|
21
|
+
"dev:server-demo": "tsx tests/smoke-e2e/server-demo.ts",
|
|
22
|
+
"dev:client-demo": "tsx tests/smoke-e2e/client-demo.ts",
|
|
21
23
|
"prepublishOnly": "npm run typecheck && npm run build && npm run test:run"
|
|
22
24
|
},
|
|
23
25
|
"peerDependencies": {},
|
|
@@ -62,5 +64,12 @@
|
|
|
62
64
|
"ai",
|
|
63
65
|
"llm",
|
|
64
66
|
"agents"
|
|
65
|
-
]
|
|
67
|
+
],
|
|
68
|
+
"repository": {
|
|
69
|
+
"type": "git",
|
|
70
|
+
"url": "https://github.com/code-rabi/toolception.git"
|
|
71
|
+
},
|
|
72
|
+
"bugs": {
|
|
73
|
+
"url": "https://github.com/code-rabi/toolception/issues"
|
|
74
|
+
}
|
|
66
75
|
}
|