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 CHANGED
@@ -75,14 +75,25 @@ const configSchema = {
75
75
  } as const;
76
76
  ```
77
77
 
78
- ### Step 7: Create and start the MCP server
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
- Creates an MCP server with dynamic/static tool management and Fastify HTTP transport.
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
- - Limits and namespacing for registered tools (e.g., `maxActiveToolsets`, `namespaceToolsWithSetKey`, `allowlist`/`denylist`).
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.mcp (optional)
299
+ #### options.createServer (optional)
176
300
 
177
- `{ name?: string; version?: string; capabilities?: Record<string, unknown> }`
301
+ `() => McpServer`
178
302
 
179
- - Overrides MCP server identity and capabilities; `tools.listChanged` is set automatically based on mode.
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 { McpServer as y } from "@modelcontextprotocol/sdk/server/mcp.js";
2
- import { z as g } from "zod";
3
- import S from "fastify";
4
- import I from "@fastify/cors";
5
- import { randomUUID as T } from "node:crypto";
6
- import { StreamableHTTPServerTransport as $ } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
7
- import { isInitializeRequest as L } from "@modelcontextprotocol/sdk/types.js";
8
- const p = {
9
- dynamic: ["dynamic-tool-discovery", "dynamicToolDiscovery", "DYNAMIC_TOOL_DISCOVERY"],
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 D {
15
+ class S {
13
16
  constructor(e = {}) {
14
17
  this.keys = {
15
- dynamic: e.keys?.dynamic ?? p.dynamic,
16
- toolsets: e.keys?.toolsets ?? p.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((r) => r.trim()).filter((r) => r.length > 0), o = new Set(Object.keys(s)), i = [];
25
- for (const r of t)
26
- o.has(r) ? i.push(r) : console.warn(`Invalid toolset '${r}' ignored. Available: ${Array.from(o).join(", ")}`);
27
- return i;
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 i = s[o];
33
- i && (i.modules || []).forEach((r) => t.add(r));
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 { isValid: !1, error: `Invalid toolset name provided. Must be a non-empty string. Available toolsets: ${Object.keys(s).join(", ")}` };
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 ? { isValid: !1, error: `Empty toolset name provided. Available toolsets: ${Object.keys(s).join(", ")}` } : s[t] ? { isValid: !0, sanitized: t } : { isValid: !1, error: `Toolset '${t}' not found. Available toolsets: ${Object.keys(s).join(", ")}` };
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 ? { isValid: !1, error: `No modules found for toolsets: ${e.join(", ")}` } : { isValid: !0, modules: t };
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 { isValid: !1, error: `Error resolving modules for ${e.join(", ")}: ${t instanceof Error ? t.message : "Unknown error"}` };
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) return t;
92
+ if (typeof t == "string" && t.trim().length > 0)
93
+ return t;
65
94
  }
66
95
  }
67
96
  }
68
- class E {
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 i = this.catalog[o];
103
- if (i && (Array.isArray(i.tools) && i.tools.length > 0 && t.push(...i.tools), Array.isArray(i.modules) && i.modules.length > 0))
104
- for (const r of i.modules) {
105
- const l = this.moduleLoaders[r];
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 a = await l(s);
109
- Array.isArray(a) && a.length > 0 && t.push(...a);
110
- } catch (a) {
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 '${r}' failed for toolset '${o}':`,
113
- a
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 v extends Error {
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 A {
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 v(
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 v(
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 N {
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 A({ namespaceWithToolset: !0 });
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 i = this.toolRegistry.mapAndValidate(
254
+ const r = this.toolRegistry.mapAndValidate(
226
255
  t,
227
256
  o
228
257
  );
229
- this.registerDirectTools(i, t);
258
+ this.registerDirectTools(r, t);
230
259
  }
231
260
  this.activeToolsets.add(t);
232
261
  try {
233
262
  await this.onToolsListChanged?.();
234
- } catch (i) {
235
- console.warn("Failed to send tool list change notification:", i);
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 i of e)
316
+ for (const r of e)
288
317
  try {
289
- const r = await this.enableToolset(i);
290
- s.push({ name: i, ...r });
291
- } catch (r) {
318
+ const i = await this.enableToolset(r);
319
+ s.push({ name: r, ...i });
320
+ } catch (i) {
292
321
  s.push({
293
- name: i,
322
+ name: r,
294
323
  success: !1,
295
- message: r instanceof Error ? r.message : "Unknown error",
324
+ message: i instanceof Error ? i.message : "Unknown error",
296
325
  code: "E_INTERNAL"
297
326
  });
298
327
  }
299
- const t = s.every((i) => i.success), o = t ? "All toolsets enabled" : "Some toolsets failed to enable";
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 P(n, e, s) {
354
+ function M(a, e, s) {
326
355
  const t = s?.mode ?? "DYNAMIC";
327
- n.tool(
356
+ a.tool(
328
357
  "enable_toolset",
329
358
  "Enable a toolset by name",
330
- { name: g.string().describe("Toolset name") },
359
+ { name: u.string().describe("Toolset name") },
331
360
  async (o) => {
332
- const { name: i } = o, r = await e.enableToolset(i);
361
+ const { name: r } = o, i = await e.enableToolset(r);
333
362
  return {
334
- content: [{ type: "text", text: JSON.stringify(r) }]
363
+ content: [{ type: "text", text: JSON.stringify(i) }]
335
364
  };
336
365
  }
337
- ), n.tool(
366
+ ), a.tool(
338
367
  "disable_toolset",
339
368
  "Disable a toolset by name (state only)",
340
- { name: g.string().describe("Toolset name") },
369
+ { name: u.string().describe("Toolset name") },
341
370
  async (o) => {
342
- const { name: i } = o, r = await e.disableToolset(i);
371
+ const { name: r } = o, i = await e.disableToolset(r);
343
372
  return {
344
- content: [{ type: "text", text: JSON.stringify(r) }]
373
+ content: [{ type: "text", text: JSON.stringify(i) }]
345
374
  };
346
375
  }
347
- ), t === "DYNAMIC" && (n.tool(
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(), i = e.getStatus().toolsetToTools, r = o.map((l) => {
353
- const a = e.getToolsetDefinition(l);
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: a ? {
358
- name: a.name,
359
- description: a.description,
360
- modules: a.modules ?? [],
361
- decisionCriteria: a.decisionCriteria ?? void 0
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: i[l] ?? []
392
+ tools: r[l] ?? []
364
393
  };
365
394
  });
366
395
  return {
367
396
  content: [
368
- { type: "text", text: JSON.stringify({ toolsets: r }) }
397
+ { type: "text", text: JSON.stringify({ toolsets: i }) }
369
398
  ]
370
399
  };
371
400
  }
372
- ), n.tool(
401
+ ), a.tool(
373
402
  "describe_toolset",
374
403
  "Describe a toolset with definition, active status and tools",
375
- { name: g.string().describe("Toolset name") },
404
+ { name: u.string().describe("Toolset name") },
376
405
  async (o) => {
377
- const { name: i } = o, r = e.getToolsetDefinition(i), l = e.getStatus().toolsetToTools;
378
- if (!r)
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 '${i}'` })
412
+ text: JSON.stringify({ error: `Unknown toolset '${r}'` })
384
413
  }
385
414
  ]
386
415
  };
387
- const a = {
388
- key: i,
389
- active: e.isActive(i),
416
+ const n = {
417
+ key: r,
418
+ active: e.isActive(r),
390
419
  definition: {
391
- name: r.name,
392
- description: r.description,
393
- modules: r.modules ?? [],
394
- decisionCriteria: r.decisionCriteria ?? void 0
420
+ name: i.name,
421
+ description: i.description,
422
+ modules: i.modules ?? [],
423
+ decisionCriteria: i.decisionCriteria ?? void 0
395
424
  },
396
- tools: l[i] ?? []
425
+ tools: l[r] ?? []
397
426
  };
398
427
  return {
399
- content: [{ type: "text", text: JSON.stringify(a) }]
428
+ content: [{ type: "text", text: JSON.stringify(n) }]
400
429
  };
401
430
  }
402
- )), n.tool(
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(), i = {
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(i) }]
441
+ content: [{ type: "text", text: JSON.stringify(r) }]
413
442
  };
414
443
  }
415
444
  );
416
445
  }
417
- class b {
446
+ class y {
418
447
  constructor(e) {
419
- new D();
420
- const s = e.startup ?? {};
421
- this.mode = s.mode ?? "DYNAMIC", this.resolver = new E({
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 t = new A({
454
+ const o = new v({
426
455
  namespaceWithToolset: e.exposurePolicy?.namespaceToolsWithSetKey ?? !0
427
456
  });
428
- this.manager = new N({
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: t
435
- }), e.registerMetaTools !== !1 && P(e.server, this.manager, { mode: this.mode });
436
- const o = s.toolsets;
437
- o === "ALL" ? this.manager.enableToolsets(this.resolver.getAvailableToolsets()) : Array.isArray(o) && o.length > 0 && this.manager.enableToolsets(o);
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 j {
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 O {
550
+ class L {
487
551
  constructor(e, s, t = {}, o) {
488
- this.app = null, this.clientCache = new j(), this.defaultManager = e, this.createBundle = s, this.options = {
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 ?? S({ logger: this.options.logger });
500
- this.options.cors && await e.register(I, { origin: !0 });
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 i = t.headers["mcp-client-id"]?.trim(), r = i && i.length > 0 ? i : `anon-${T()}`, l = !r.startsWith("anon-");
515
- let a = l ? this.clientCache.get(r) : null;
516
- if (!a) {
517
- const u = this.createBundle();
518
- a = {
519
- server: u.server,
520
- orchestrator: u.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(r, a);
586
+ }, l && this.clientCache.set(i, n);
523
587
  }
524
- const d = t.headers["mcp-session-id"];
525
- let h;
526
- if (d && a.sessions.get(d))
527
- h = a.sessions.get(d);
528
- else if (!d && L(t.body)) {
529
- const u = T();
530
- h = new $({
531
- sessionIdGenerator: () => u,
532
- onsessioninitialized: (c) => {
533
- a.sessions.set(c, h);
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 a.server.connect(h);
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
- h.onclose = () => {
546
- h?.sessionId && a.sessions.delete(h.sessionId);
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 h.handleRequest(
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 i = t.headers["mcp-client-id"]?.trim(), r = i && i.length > 0 ? i : "";
562
- if (!r)
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(r);
628
+ const l = this.clientCache.get(i);
565
629
  if (!l)
566
630
  return o.code(400), "Invalid or expired client";
567
- const a = t.headers["mcp-session-id"];
568
- if (!a)
631
+ const n = t.headers["mcp-session-id"];
632
+ if (!n)
569
633
  return o.code(400), "Missing mcp-session-id";
570
- const d = l.sessions.get(a);
571
- return d ? (await d.handleRequest(t.raw, o.raw), o) : (o.code(400), "Invalid or expired session ID");
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 i = t.headers["mcp-client-id"]?.trim(), r = i && i.length > 0 ? i : "", l = t.headers["mcp-session-id"];
576
- if (!r || !l)
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 a = this.clientCache.get(r), d = a?.sessions.get(l);
586
- return !a || !d ? (o.code(404), {
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 U(n) {
599
- const e = n.startup?.mode ?? "DYNAMIC", s = n.mcp?.name ?? "mcp-dynamic-tooling", t = n.mcp?.version ?? "0.0.0", o = n.mcp?.capabilities ?? {}, i = {
600
- ...o,
601
- tools: {
602
- ...typeof o.tools == "object" ? o.tools : {},
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 (l(c)) {
613
- await c.server.notification({
668
+ if (t(n)) {
669
+ await n.server.notification({
614
670
  method: "notifications/tools/list_changed"
615
671
  });
616
672
  return;
617
673
  }
618
- a(c) && await c.notifyToolsListChanged();
674
+ o(n) && await n.notifyToolsListChanged();
619
675
  } catch {
620
676
  }
621
- }, h = new b({
622
- server: r,
623
- catalog: n.catalog,
624
- moduleLoaders: n.moduleLoaders,
625
- exposurePolicy: n.exposurePolicy,
626
- context: n.context,
627
- notifyToolsListChanged: async () => d(r),
628
- startup: n.startup,
629
- registerMetaTools: n.registerMetaTools !== void 0 ? n.registerMetaTools : e === "DYNAMIC"
630
- }), u = new O(
631
- h.getManager(),
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 c = n.startup?.mode ?? "DYNAMIC", w = n.mcp?.name ?? s, x = n.mcp?.version ?? t, f = n.mcp?.capabilities ?? o, M = {
634
- ...f,
635
- tools: {
636
- ...typeof f.tools == "object" ? f.tools : {},
637
- listChanged: c === "DYNAMIC"
638
- }
639
- }, m = new y({
640
- name: w,
641
- version: x,
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: m, orchestrator: C };
699
+ return { server: n, orchestrator: c };
654
700
  },
655
- n.http,
656
- n.configSchema
701
+ a.http,
702
+ a.configSchema
657
703
  );
658
704
  return {
659
- server: r,
705
+ server: s,
660
706
  start: async () => {
661
- await u.start();
707
+ await l.start();
662
708
  },
663
709
  close: async () => {
664
- await u.stop();
710
+ await l.stop();
665
711
  }
666
712
  };
667
713
  }
668
714
  export {
669
- U as createMcpServer
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.0",
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
  }