toolception 0.2.5 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/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\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 const providedSessions = (created as any).sessions;\n bundle = {\n server: created.server,\n orchestrator: created.orchestrator,\n sessions:\n providedSessions instanceof Map ? providedSessions : 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 try {\n // Best-effort close and evict\n if (typeof (transport as any).close === \"function\") {\n try {\n await (transport as any).close();\n } catch {}\n }\n } finally {\n if (transport?.sessionId) bundle.sessions.delete(transport.sessionId);\n else bundle.sessions.delete(sessionId);\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 if (mode === \"STATIC\") {\n // Reuse the base server and orchestrator to avoid duplicate registrations\n return { server: baseServer, orchestrator };\n }\n const createdServer: McpServer = options.createServer();\n const createdOrchestrator = 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: createdOrchestrator };\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","providedSessions","sessionId","transport","isInitializeRequest","newSessionId","StreamableHTTPServerTransport","sid","createMcpServer","baseServer","hasNotifierA","hasNotifierB","notifyToolsChanged","target","orchestrator","createdServer","createdOrchestrator"],"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","../src/permissions/validatePermissionConfig.ts","../src/permissions/PermissionResolver.ts","../src/permissions/createPermissionAwareBundle.ts","../src/permissions/PermissionAwareFastifyTransport.ts","../src/server/createPermissionBasedMcpServer.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 const providedSessions = (created as any).sessions;\n bundle = {\n server: created.server,\n orchestrator: created.orchestrator,\n sessions:\n providedSessions instanceof Map ? providedSessions : 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 try {\n // Best-effort close and evict\n if (typeof (transport as any).close === \"function\") {\n try {\n await (transport as any).close();\n } catch {}\n }\n } finally {\n if (transport?.sessionId) bundle.sessions.delete(transport.sessionId);\n else bundle.sessions.delete(sessionId);\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 if (mode === \"STATIC\") {\n // Reuse the base server and orchestrator to avoid duplicate registrations\n return { server: baseServer, orchestrator };\n }\n const createdServer: McpServer = options.createServer();\n const createdOrchestrator = 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: createdOrchestrator };\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","import type { PermissionConfig } from \"../types/index.js\";\n\n/**\n * Validates a permission configuration object to ensure it meets all requirements.\n * Throws descriptive errors for any validation failures.\n * @param config - The permission configuration to validate\n * @throws {Error} If the configuration is invalid or missing required fields\n */\nexport function validatePermissionConfig(config: PermissionConfig): void {\n validateConfigExists(config);\n validateSourceField(config);\n validateConfigBasedPermissions(config);\n validateTypes(config);\n}\n\n/**\n * Validates that the configuration object exists.\n * @param config - The permission configuration to validate\n * @throws {Error} If config is null, undefined, or not an object\n * @private\n */\nfunction validateConfigExists(config: PermissionConfig): void {\n if (!config || typeof config !== \"object\") {\n throw new Error(\n \"Permission configuration is required for createPermissionBasedMcpServer\"\n );\n }\n}\n\n/**\n * Validates that the source field is present and has a valid value.\n * @param config - The permission configuration to validate\n * @throws {Error} If source is missing or not 'headers' or 'config'\n * @private\n */\nfunction validateSourceField(config: PermissionConfig): void {\n if (!config.source) {\n throw new Error('Permission source must be either \"headers\" or \"config\"');\n }\n\n if (config.source !== \"headers\" && config.source !== \"config\") {\n throw new Error(\n `Invalid permission source: \"${config.source}\". Must be either \"headers\" or \"config\"`\n );\n }\n}\n\n/**\n * Validates config-based permission requirements.\n * When source is 'config', at least one of staticMap or resolver must be provided.\n * @param config - The permission configuration to validate\n * @throws {Error} If config source is used but neither staticMap nor resolver is provided\n * @private\n */\nfunction validateConfigBasedPermissions(config: PermissionConfig): void {\n if (config.source === \"config\") {\n if (!config.staticMap && !config.resolver) {\n throw new Error(\n \"Config-based permissions require at least one of: staticMap or resolver function\"\n );\n }\n }\n}\n\n/**\n * Validates the types of configuration fields.\n * Ensures staticMap is an object and resolver is a function when provided.\n * @param config - The permission configuration to validate\n * @throws {Error} If staticMap or resolver have incorrect types\n * @private\n */\nfunction validateTypes(config: PermissionConfig): void {\n if (config.staticMap !== undefined) {\n if (typeof config.staticMap !== \"object\" || config.staticMap === null) {\n throw new Error(\n \"staticMap must be an object mapping client IDs to toolset arrays\"\n );\n }\n\n // Validate that staticMap values are arrays\n validateStaticMapValues(config.staticMap);\n }\n\n if (config.resolver !== undefined) {\n if (typeof config.resolver !== \"function\") {\n throw new Error(\n \"resolver must be a synchronous function: (clientId: string) => string[]\"\n );\n }\n }\n\n if (config.defaultPermissions !== undefined) {\n if (!Array.isArray(config.defaultPermissions)) {\n throw new Error(\"defaultPermissions must be an array of toolset names\");\n }\n }\n\n if (config.headerName !== undefined) {\n if (typeof config.headerName !== \"string\" || config.headerName.length === 0) {\n throw new Error(\"headerName must be a non-empty string\");\n }\n }\n}\n\n/**\n * Validates that all values in the staticMap are arrays.\n * @param staticMap - The static map to validate\n * @throws {Error} If any value in the staticMap is not an array\n * @private\n */\nfunction validateStaticMapValues(staticMap: Record<string, string[]>): void {\n for (const [clientId, permissions] of Object.entries(staticMap)) {\n if (!Array.isArray(permissions)) {\n throw new Error(\n `staticMap value for client \"${clientId}\" must be an array of toolset names`\n );\n }\n }\n}\n","import type { PermissionConfig } from \"../types/index.js\";\n\n/**\n * Resolves and caches client permissions based on configured permission sources.\n * Supports both header-based and config-based permission resolution with caching\n * for performance optimization.\n */\nexport class PermissionResolver {\n private cache = new Map<string, string[]>();\n\n /**\n * Creates a new PermissionResolver instance.\n * @param config - The permission configuration defining how permissions are resolved\n */\n constructor(private config: PermissionConfig) {}\n\n /**\n * Resolves permissions for a client based on the configured source.\n * Results are cached to improve performance for subsequent requests from the same client.\n * Handles all errors gracefully by returning empty permissions on failure.\n * @param clientId - The unique identifier for the client\n * @param headers - Optional request headers (required for header-based permissions)\n * @returns Array of toolset names the client is allowed to access\n */\n resolvePermissions(\n clientId: string,\n headers?: Record<string, string>\n ): string[] {\n // Check cache first for performance\n if (this.cache.has(clientId)) {\n return this.cache.get(clientId)!;\n }\n\n let permissions: string[];\n\n try {\n if (this.config.source === \"headers\") {\n permissions = this.#parseHeaderPermissions(headers);\n } else {\n permissions = this.#resolveConfigPermissions(clientId);\n }\n\n // Validate that permissions is an array\n if (!Array.isArray(permissions)) {\n console.warn(\n `Permission resolution returned non-array for client ${clientId}, using empty permissions`\n );\n permissions = [];\n }\n\n // Filter out invalid toolset names (empty strings, non-strings)\n permissions = permissions.filter(\n (name) => typeof name === \"string\" && name.trim().length > 0\n );\n } catch (error) {\n // Catch any unexpected errors and apply most restrictive permissions\n console.error(\n `Unexpected error resolving permissions for client ${clientId}:`,\n error\n );\n permissions = [];\n }\n\n // Cache the resolved permissions\n this.cache.set(clientId, permissions);\n return permissions;\n }\n\n /**\n * Parses permissions from request headers.\n * Extracts comma-separated toolset names from the configured header.\n * Handles malformed headers gracefully by returning empty permissions.\n * @param headers - Request headers containing permission data\n * @returns Array of toolset names from headers, or empty array if header is missing/malformed\n * @private\n */\n #parseHeaderPermissions(headers?: Record<string, string>): string[] {\n const headerName = this.config.headerName || \"mcp-toolset-permissions\";\n const headerValue = headers?.[headerName];\n\n if (!headerValue) {\n return [];\n }\n\n try {\n // Parse comma-separated list, trim whitespace, and filter empty strings\n return headerValue\n .split(\",\")\n .map((s) => s.trim())\n .filter((s) => s.length > 0);\n } catch (error) {\n // Handle malformed headers gracefully\n console.warn(\n `Failed to parse permission header '${headerName}':`,\n error\n );\n return [];\n }\n }\n\n /**\n * Resolves permissions from server-side configuration.\n * Tries resolver function first (if provided), then falls back to static map,\n * and finally to default permissions. Handles errors gracefully.\n * @param clientId - The unique identifier for the client\n * @returns Array of toolset names from configuration\n * @private\n */\n #resolveConfigPermissions(clientId: string): string[] {\n // Try resolver function first (if provided)\n if (this.config.resolver) {\n const resolverResult = this.#tryResolverFunction(clientId);\n if (resolverResult !== null) {\n return resolverResult;\n }\n // Fall through to static map or default if resolver fails\n }\n\n // Fall back to static map (if provided)\n if (this.config.staticMap) {\n const staticResult = this.#lookupStaticMap(clientId);\n if (staticResult !== null) {\n return staticResult;\n }\n }\n\n // Final fallback to default permissions\n return this.config.defaultPermissions || [];\n }\n\n /**\n * Attempts to resolve permissions using the configured resolver function.\n * Handles errors gracefully and returns null on failure to allow fallback.\n * @param clientId - The unique identifier for the client\n * @returns Array of toolset names if successful, null if resolver fails or returns invalid data\n * @private\n */\n #tryResolverFunction(clientId: string): string[] | null {\n try {\n const result = this.config.resolver!(clientId);\n if (Array.isArray(result)) {\n return result;\n }\n console.warn(\n `Permission resolver returned non-array for client ${clientId}, using fallback`\n );\n return null;\n } catch (error) {\n // Log message only, not full stack trace (this is expected fallback behavior)\n const message = error instanceof Error ? error.message : String(error);\n console.warn(\n `Permission resolver declined client ${clientId} (${message}), trying fallback`\n );\n return null;\n }\n }\n\n /**\n * Looks up permissions in the static map configuration.\n * Returns null if client is not found to allow fallback to defaults.\n * @param clientId - The unique identifier for the client\n * @returns Array of toolset names if found, null if client not in map\n * @private\n */\n #lookupStaticMap(clientId: string): string[] | null {\n const permissions = this.config.staticMap![clientId];\n if (permissions !== undefined) {\n return Array.isArray(permissions) ? permissions : [];\n }\n return null;\n }\n\n /**\n * Clears the permission cache.\n * Useful for cleanup during server shutdown or when permissions need to be refreshed.\n */\n clearCache(): void {\n this.cache.clear();\n }\n}\n","import type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport type { ServerOrchestrator } from \"../core/ServerOrchestrator.js\";\nimport type { PermissionResolver } from \"./PermissionResolver.js\";\n\n/**\n * Context information extracted from a client request.\n * Used to identify the client and resolve their permissions.\n */\nexport interface ClientRequestContext {\n /**\n * Unique identifier for the client making the request.\n * May be provided via mcp-client-id header or generated as anonymous ID.\n */\n clientId: string;\n\n /**\n * Request headers that may contain permission data.\n * Used for header-based permission resolution.\n */\n headers?: Record<string, string>;\n}\n\n/**\n * Result of permission-aware bundle creation, including the resolved permissions.\n */\nexport interface PermissionAwareBundle {\n /**\n * The MCP server instance for this client.\n */\n server: McpServer;\n\n /**\n * The orchestrator managing toolsets for this client.\n */\n orchestrator: ServerOrchestrator;\n\n /**\n * The resolved permissions (allowed toolsets) for this client.\n */\n allowedToolsets: string[];\n}\n\n/**\n * Creates a permission-aware bundle creation function that wraps the original\n * createBundle function with permission resolution and enforcement.\n *\n * This function resolves client permissions and passes them to the bundle creator,\n * which creates a server with STATIC mode configured to only those toolsets.\n *\n * @param originalCreateBundle - Bundle creation function that accepts allowed toolsets\n * @param permissionResolver - Resolver instance for determining client permissions\n * @returns Enhanced bundle creation function that accepts client context\n */\nexport function createPermissionAwareBundle(\n originalCreateBundle: (allowedToolsets: string[]) => {\n server: McpServer;\n orchestrator: ServerOrchestrator;\n },\n permissionResolver: PermissionResolver\n) {\n /**\n * Creates a server bundle with permission-based toolset access control.\n * Resolves client permissions and creates a server with those toolsets pre-loaded.\n *\n * This function is async to ensure toolsets are fully loaded before the server\n * is connected to a transport.\n *\n * @param context - Client request context containing ID and headers\n * @returns Promise resolving to server bundle with resolved permissions\n */\n return async (context: ClientRequestContext): Promise<PermissionAwareBundle> => {\n // Resolve permissions for this client\n const allowedToolsets = permissionResolver.resolvePermissions(\n context.clientId,\n context.headers\n );\n\n // Create bundle with allowed toolsets (STATIC mode pre-loads them)\n const bundle = originalCreateBundle(allowedToolsets);\n\n // Wait for toolsets to be enabled before returning\n // This ensures tools are registered before the server connects to transport\n const manager = bundle.orchestrator.getManager();\n if (allowedToolsets.length > 0) {\n await manager.enableToolsets(allowedToolsets);\n }\n\n // Return bundle with resolved permissions\n return {\n server: bundle.server,\n orchestrator: bundle.orchestrator,\n allowedToolsets,\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 { 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\";\nimport type { ServerOrchestrator } from \"../core/ServerOrchestrator.js\";\nimport type {\n ClientRequestContext,\n PermissionAwareBundle,\n} from \"./createPermissionAwareBundle.js\";\n\nexport interface PermissionAwareFastifyTransportOptions {\n host?: string;\n port?: number;\n basePath?: string;\n cors?: boolean;\n logger?: boolean;\n app?: FastifyInstance;\n}\n\n/**\n * Enhanced Fastify transport that supports permission-based toolset access.\n * Integrates with PermissionResolver to enforce per-client toolset permissions.\n * \n * This transport extracts client context from requests and passes it to the\n * permission-aware bundle creator, ensuring each client receives only their\n * authorized toolsets while maintaining session management and caching.\n */\nexport class PermissionAwareFastifyTransport {\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 createPermissionAwareBundle: (\n context: ClientRequestContext\n ) => Promise<PermissionAwareBundle>;\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 allowedToolsets: string[];\n }>();\n\n /**\n * Creates a new PermissionAwareFastifyTransport instance.\n * @param defaultManager - Default tool manager for status endpoints\n * @param createPermissionAwareBundle - Function to create permission-aware bundles\n * @param options - Transport configuration options\n * @param configSchema - Optional JSON schema for configuration discovery\n */\n constructor(\n defaultManager: DynamicToolManager,\n createPermissionAwareBundle: (\n context: ClientRequestContext\n ) => Promise<PermissionAwareBundle>,\n options: PermissionAwareFastifyTransportOptions = {},\n configSchema?: object\n ) {\n this.defaultManager = defaultManager;\n this.createPermissionAwareBundle = createPermissionAwareBundle;\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 /**\n * Starts the Fastify server and registers all MCP endpoints.\n * Sets up routes for health checks, tool status, and MCP protocol handling.\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.#normalizeBasePath(this.options.basePath);\n\n this.#registerHealthEndpoint(app, base);\n this.#registerToolsEndpoint(app, base);\n this.#registerConfigDiscoveryEndpoint(app, base);\n this.#registerMcpPostEndpoint(app, base);\n this.#registerMcpGetEndpoint(app, base);\n this.#registerMcpDeleteEndpoint(app, base);\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 /**\n * Stops the Fastify server and cleans up resources.\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 /**\n * Normalizes the base path by removing trailing slashes.\n * @param basePath - The base path to normalize\n * @returns Normalized base path without trailing slash\n * @private\n */\n #normalizeBasePath(basePath: string): string {\n return basePath.endsWith(\"/\") ? basePath.slice(0, -1) : basePath;\n }\n\n /**\n * Registers the health check endpoint.\n * @param app - Fastify instance\n * @param base - Base path for routes\n * @private\n */\n #registerHealthEndpoint(app: FastifyInstance, base: string): void {\n app.get(`${base}/healthz`, async () => ({ ok: true }));\n }\n\n /**\n * Registers the tools status endpoint.\n * @param app - Fastify instance\n * @param base - Base path for routes\n * @private\n */\n #registerToolsEndpoint(app: FastifyInstance, base: string): void {\n app.get(`${base}/tools`, async () => this.defaultManager.getStatus());\n }\n\n /**\n * Registers the MCP configuration discovery endpoint.\n * @param app - Fastify instance\n * @param base - Base path for routes\n * @private\n */\n #registerConfigDiscoveryEndpoint(app: FastifyInstance, base: string): void {\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\n /**\n * Registers the POST /mcp endpoint for JSON-RPC requests.\n * Extracts client context, resolves permissions, and handles MCP protocol.\n * @param app - Fastify instance\n * @param base - Base path for routes\n * @private\n */\n #registerMcpPostEndpoint(app: FastifyInstance, base: string): void {\n app.post(\n `${base}/mcp`,\n async (req: FastifyRequest, reply: FastifyReply) => {\n // Extract client context from request\n const context = this.#extractClientContext(req);\n\n // Determine if we should cache this client's bundle\n const useCache = !context.clientId.startsWith(\"anon-\");\n\n // Get or create permission-aware bundle for this client\n let bundle = useCache ? this.clientCache.get(context.clientId) : null;\n if (!bundle) {\n try {\n const created = await this.createPermissionAwareBundle(context);\n \n // Toolsets are already loaded via async bundle creation\n // No need to manually enable them\n \n const providedSessions = (created as any).sessions;\n bundle = {\n server: created.server,\n orchestrator: created.orchestrator,\n allowedToolsets: created.allowedToolsets,\n sessions:\n providedSessions instanceof Map ? providedSessions : new Map(),\n };\n if (useCache) this.clientCache.set(context.clientId, bundle);\n } catch (error) {\n // Handle permission resolution or bundle creation failures\n console.error(\n `Failed to create permission-aware bundle for client ${context.clientId}:`,\n error\n );\n reply.code(403);\n return this.#createSafeErrorResponse(\"Access denied\");\n }\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 return reply;\n }\n );\n }\n\n /**\n * Registers the GET /mcp endpoint for SSE notifications.\n * @param app - Fastify instance\n * @param base - Base path for routes\n * @private\n */\n #registerMcpGetEndpoint(app: FastifyInstance, base: string): void {\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\n /**\n * Registers the DELETE /mcp endpoint for session termination.\n * @param app - Fastify instance\n * @param base - Base path for routes\n * @private\n */\n #registerMcpDeleteEndpoint(app: FastifyInstance, base: string): void {\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 try {\n // Best-effort close and evict\n if (typeof (transport as any).close === \"function\") {\n try {\n await (transport as any).close();\n } catch {}\n }\n } finally {\n if (transport?.sessionId) bundle.sessions.delete(transport.sessionId);\n else bundle.sessions.delete(sessionId);\n }\n reply.code(204).send();\n return reply;\n }\n );\n }\n\n /**\n * Extracts client context from the request.\n * Generates anonymous client ID if not provided in headers.\n * @param req - Fastify request object\n * @returns Client request context with ID and headers\n * @private\n */\n #extractClientContext(req: FastifyRequest): ClientRequestContext {\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 // Convert headers to plain object for permission resolution\n const headers: Record<string, string> = {};\n for (const [key, value] of Object.entries(req.headers)) {\n if (typeof value === \"string\") {\n headers[key] = value;\n }\n }\n\n return { clientId, headers };\n }\n\n /**\n * Creates a safe error response that doesn't expose unauthorized toolset information.\n * Used for permission-related errors to prevent information leakage.\n * @param message - Generic error message to return to client\n * @param code - JSON-RPC error code (default: -32000 for server error)\n * @returns JSON-RPC error response object\n * @private\n */\n #createSafeErrorResponse(message: string = \"Access denied\", code: number = -32000) {\n return {\n jsonrpc: \"2.0\" as const,\n error: {\n code,\n message,\n },\n id: null,\n };\n }\n}\n","import type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport type { CreatePermissionBasedMcpServerOptions } from \"../types/index.js\";\nimport { validatePermissionConfig } from \"../permissions/validatePermissionConfig.js\";\nimport { PermissionResolver } from \"../permissions/PermissionResolver.js\";\nimport { ServerOrchestrator } from \"../core/ServerOrchestrator.js\";\nimport { createPermissionAwareBundle } from \"../permissions/createPermissionAwareBundle.js\";\nimport { PermissionAwareFastifyTransport } from \"../permissions/PermissionAwareFastifyTransport.js\";\n\n/**\n * Creates an MCP server with permission-based toolset access control.\n *\n * This function provides a separate API for creating servers where each client receives\n * only the toolsets they're authorized to access. Each client gets a fresh server instance\n * with STATIC mode configured to their allowed toolsets, ensuring per-client isolation\n * without meta-tools or dynamic loading.\n *\n * The server supports two permission sources:\n * - **Header-based**: Permissions are read from request headers (e.g., `mcp-toolset-permissions`)\n * - **Config-based**: Permissions are resolved server-side using static maps or resolver functions\n *\n * @param options - Configuration options including permission settings, catalog, and HTTP transport options\n * @returns Server instance with `server`, `start()`, and `close()` methods matching the createMcpServer interface\n * @throws {Error} If permission configuration is invalid, missing, or if startup.mode is provided\n *\n * @example\n * // Header-based permissions\n * const server = await createPermissionBasedMcpServer({\n * createServer: () => new McpServer({ name: \"my-server\", version: \"1.0.0\" }),\n * catalog: { toolsetA: { name: \"Toolset A\", tools: [...] } },\n * permissions: {\n * source: 'headers',\n * headerName: 'mcp-toolset-permissions' // optional, this is the default\n * }\n * });\n *\n * @example\n * // Config-based permissions with static map\n * const server = await createPermissionBasedMcpServer({\n * createServer: () => new McpServer({ name: \"my-server\", version: \"1.0.0\" }),\n * catalog: { toolsetA: { name: \"Toolset A\", tools: [...] } },\n * permissions: {\n * source: 'config',\n * staticMap: {\n * 'client-1': ['toolsetA', 'toolsetB'],\n * 'client-2': ['toolsetC']\n * },\n * defaultPermissions: [] // optional, defaults to empty array\n * }\n * });\n *\n * @example\n * // Config-based permissions with resolver function\n * const server = await createPermissionBasedMcpServer({\n * createServer: () => new McpServer({ name: \"my-server\", version: \"1.0.0\" }),\n * catalog: { toolsetA: { name: \"Toolset A\", tools: [...] } },\n * permissions: {\n * source: 'config',\n * resolver: (clientId) => {\n * // Your custom logic to determine permissions\n * return clientId.startsWith('admin-') ? ['toolsetA', 'toolsetB'] : ['toolsetA'];\n * },\n * defaultPermissions: ['toolsetA'] // fallback if resolver fails\n * }\n * });\n */\nexport async function createPermissionBasedMcpServer(\n options: CreatePermissionBasedMcpServerOptions\n) {\n // Validate that permissions field is provided\n if (!options.permissions) {\n throw new Error(\n \"Permission configuration is required for createPermissionBasedMcpServer. \" +\n \"Please provide a 'permissions' field in the options.\"\n );\n }\n\n // Validate permission configuration\n validatePermissionConfig(options.permissions);\n\n // Prevent startup.mode configuration - permissions determine toolsets\n if ((options as any).startup) {\n throw new Error(\n \"Permission-based servers determine toolsets from client permissions. \" +\n \"The 'startup' option is not allowed. Remove it from your configuration.\"\n );\n }\n\n // Validate createServer factory is provided\n if (typeof options.createServer !== \"function\") {\n throw new Error(\n \"createPermissionBasedMcpServer: `createServer` (factory) is required\"\n );\n }\n\n // Create permission resolver instance\n const permissionResolver = new PermissionResolver(options.permissions);\n\n // Create base server for default manager (used for status endpoints)\n const baseServer: McpServer = options.createServer();\n\n // Create base orchestrator for default manager (empty toolsets for status endpoint)\n // No notifier needed - STATIC mode with fixed toolsets per client\n const baseOrchestrator = new ServerOrchestrator({\n server: baseServer,\n catalog: options.catalog,\n moduleLoaders: options.moduleLoaders,\n exposurePolicy: options.exposurePolicy,\n context: options.context,\n notifyToolsListChanged: undefined, // No notifications in STATIC mode\n startup: { mode: \"STATIC\", toolsets: [] },\n registerMetaTools: false,\n });\n\n // Create permission-aware bundle creator\n const createBundle = createPermissionAwareBundle(\n (allowedToolsets: string[]) => {\n // Create fresh server and orchestrator for each client\n // Use STATIC mode but don't auto-enable toolsets in constructor\n // We'll enable them manually in createPermissionAwareBundle to ensure they're loaded before connection\n const clientServer: McpServer = options.createServer();\n const clientOrchestrator = new ServerOrchestrator({\n server: clientServer,\n catalog: options.catalog,\n moduleLoaders: options.moduleLoaders,\n exposurePolicy: options.exposurePolicy,\n context: options.context,\n notifyToolsListChanged: undefined, // No notifications in STATIC mode\n startup: { mode: \"STATIC\", toolsets: [] }, // Empty - we'll enable manually\n registerMetaTools: false, // No meta-tools - toolsets are fixed per client\n });\n return { server: clientServer, orchestrator: clientOrchestrator };\n },\n permissionResolver\n );\n\n // Create permission-aware transport\n const transport = new PermissionAwareFastifyTransport(\n baseOrchestrator.getManager(),\n createBundle,\n options.http,\n options.configSchema\n );\n\n // Return same interface as createMcpServer\n return {\n server: baseServer,\n start: async () => {\n await transport.start();\n },\n close: async () => {\n try {\n // Stop the transport (cleans up client contexts)\n await transport.stop();\n } finally {\n // Clear permission cache\n permissionResolver.clearCache();\n }\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","t","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","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","providedSessions","sessionId","transport","isInitializeRequest","newSessionId","StreamableHTTPServerTransport","sid","createMcpServer","baseServer","hasNotifierA","hasNotifierB","notifyToolsChanged","target","orchestrator","createdServer","createdOrchestrator","validatePermissionConfig","config","validateConfigExists","validateSourceField","validateConfigBasedPermissions","validateTypes","validateStaticMapValues","staticMap","permissions","PermissionResolver","__privateAdd","_PermissionResolver_instances","headers","__privateMethod","parseHeaderPermissions_fn","resolveConfigPermissions_fn","headerName","headerValue","resolverResult","tryResolverFunction_fn","staticResult","lookupStaticMap_fn","createPermissionAwareBundle","originalCreateBundle","permissionResolver","allowedToolsets","PermissionAwareFastifyTransport","_PermissionAwareFastifyTransport_instances","normalizeBasePath_fn","registerHealthEndpoint_fn","registerToolsEndpoint_fn","registerConfigDiscoveryEndpoint_fn","registerMcpPostEndpoint_fn","registerMcpGetEndpoint_fn","registerMcpDeleteEndpoint_fn","basePath","extractClientContext_fn","createSafeErrorResponse_fn","createPermissionBasedMcpServer","baseOrchestrator","clientServer","clientOrchestrator"],"mappings":"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"}
@@ -0,0 +1,46 @@
1
+ import { FastifyInstance } from 'fastify';
2
+ import { DynamicToolManager } from '../core/DynamicToolManager.js';
3
+ import { ClientRequestContext, PermissionAwareBundle } from './createPermissionAwareBundle.js';
4
+ export interface PermissionAwareFastifyTransportOptions {
5
+ host?: string;
6
+ port?: number;
7
+ basePath?: string;
8
+ cors?: boolean;
9
+ logger?: boolean;
10
+ app?: FastifyInstance;
11
+ }
12
+ /**
13
+ * Enhanced Fastify transport that supports permission-based toolset access.
14
+ * Integrates with PermissionResolver to enforce per-client toolset permissions.
15
+ *
16
+ * This transport extracts client context from requests and passes it to the
17
+ * permission-aware bundle creator, ensuring each client receives only their
18
+ * authorized toolsets while maintaining session management and caching.
19
+ */
20
+ export declare class PermissionAwareFastifyTransport {
21
+ #private;
22
+ private readonly options;
23
+ private readonly defaultManager;
24
+ private readonly createPermissionAwareBundle;
25
+ private app;
26
+ private readonly configSchema?;
27
+ private readonly clientCache;
28
+ /**
29
+ * Creates a new PermissionAwareFastifyTransport instance.
30
+ * @param defaultManager - Default tool manager for status endpoints
31
+ * @param createPermissionAwareBundle - Function to create permission-aware bundles
32
+ * @param options - Transport configuration options
33
+ * @param configSchema - Optional JSON schema for configuration discovery
34
+ */
35
+ constructor(defaultManager: DynamicToolManager, createPermissionAwareBundle: (context: ClientRequestContext) => Promise<PermissionAwareBundle>, options?: PermissionAwareFastifyTransportOptions, configSchema?: object);
36
+ /**
37
+ * Starts the Fastify server and registers all MCP endpoints.
38
+ * Sets up routes for health checks, tool status, and MCP protocol handling.
39
+ */
40
+ start(): Promise<void>;
41
+ /**
42
+ * Stops the Fastify server and cleans up resources.
43
+ */
44
+ stop(): Promise<void>;
45
+ }
46
+ //# sourceMappingURL=PermissionAwareFastifyTransport.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PermissionAwareFastifyTransport.d.ts","sourceRoot":"","sources":["../../src/permissions/PermissionAwareFastifyTransport.ts"],"names":[],"mappings":"AAAA,OAAgB,EACd,KAAK,eAAe,EAGrB,MAAM,SAAS,CAAC;AAGjB,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AAMxE,OAAO,KAAK,EACV,oBAAoB,EACpB,qBAAqB,EACtB,MAAM,kCAAkC,CAAC;AAE1C,MAAM,WAAW,sCAAsC;IACrD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,GAAG,CAAC,EAAE,eAAe,CAAC;CACvB;AAED;;;;;;;GAOG;AACH,qBAAa,+BAA+B;;IAC1C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAOtB;IACF,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAqB;IACpD,OAAO,CAAC,QAAQ,CAAC,2BAA2B,CAER;IACpC,OAAO,CAAC,GAAG,CAAgC;IAC3C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAS;IAGvC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAKvB;IAEL;;;;;;OAMG;gBAED,cAAc,EAAE,kBAAkB,EAClC,2BAA2B,EAAE,CAC3B,OAAO,EAAE,oBAAoB,KAC1B,OAAO,CAAC,qBAAqB,CAAC,EACnC,OAAO,GAAE,sCAA2C,EACpD,YAAY,CAAC,EAAE,MAAM;IAevB;;;OAGG;IACU,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAuBnC;;OAEG;IACU,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAkSnC"}
@@ -0,0 +1,31 @@
1
+ import { PermissionConfig } from '../types/index.js';
2
+ /**
3
+ * Resolves and caches client permissions based on configured permission sources.
4
+ * Supports both header-based and config-based permission resolution with caching
5
+ * for performance optimization.
6
+ */
7
+ export declare class PermissionResolver {
8
+ #private;
9
+ private config;
10
+ private cache;
11
+ /**
12
+ * Creates a new PermissionResolver instance.
13
+ * @param config - The permission configuration defining how permissions are resolved
14
+ */
15
+ constructor(config: PermissionConfig);
16
+ /**
17
+ * Resolves permissions for a client based on the configured source.
18
+ * Results are cached to improve performance for subsequent requests from the same client.
19
+ * Handles all errors gracefully by returning empty permissions on failure.
20
+ * @param clientId - The unique identifier for the client
21
+ * @param headers - Optional request headers (required for header-based permissions)
22
+ * @returns Array of toolset names the client is allowed to access
23
+ */
24
+ resolvePermissions(clientId: string, headers?: Record<string, string>): string[];
25
+ /**
26
+ * Clears the permission cache.
27
+ * Useful for cleanup during server shutdown or when permissions need to be refreshed.
28
+ */
29
+ clearCache(): void;
30
+ }
31
+ //# sourceMappingURL=PermissionResolver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PermissionResolver.d.ts","sourceRoot":"","sources":["../../src/permissions/PermissionResolver.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAE1D;;;;GAIG;AACH,qBAAa,kBAAkB;;IAOjB,OAAO,CAAC,MAAM;IAN1B,OAAO,CAAC,KAAK,CAA+B;IAE5C;;;OAGG;gBACiB,MAAM,EAAE,gBAAgB;IAE5C;;;;;;;OAOG;IACH,kBAAkB,CAChB,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC/B,MAAM,EAAE;IAiJX;;;OAGG;IACH,UAAU,IAAI,IAAI;CAGnB"}
@@ -0,0 +1,52 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import { ServerOrchestrator } from '../core/ServerOrchestrator.js';
3
+ import { PermissionResolver } from './PermissionResolver.js';
4
+ /**
5
+ * Context information extracted from a client request.
6
+ * Used to identify the client and resolve their permissions.
7
+ */
8
+ export interface ClientRequestContext {
9
+ /**
10
+ * Unique identifier for the client making the request.
11
+ * May be provided via mcp-client-id header or generated as anonymous ID.
12
+ */
13
+ clientId: string;
14
+ /**
15
+ * Request headers that may contain permission data.
16
+ * Used for header-based permission resolution.
17
+ */
18
+ headers?: Record<string, string>;
19
+ }
20
+ /**
21
+ * Result of permission-aware bundle creation, including the resolved permissions.
22
+ */
23
+ export interface PermissionAwareBundle {
24
+ /**
25
+ * The MCP server instance for this client.
26
+ */
27
+ server: McpServer;
28
+ /**
29
+ * The orchestrator managing toolsets for this client.
30
+ */
31
+ orchestrator: ServerOrchestrator;
32
+ /**
33
+ * The resolved permissions (allowed toolsets) for this client.
34
+ */
35
+ allowedToolsets: string[];
36
+ }
37
+ /**
38
+ * Creates a permission-aware bundle creation function that wraps the original
39
+ * createBundle function with permission resolution and enforcement.
40
+ *
41
+ * This function resolves client permissions and passes them to the bundle creator,
42
+ * which creates a server with STATIC mode configured to only those toolsets.
43
+ *
44
+ * @param originalCreateBundle - Bundle creation function that accepts allowed toolsets
45
+ * @param permissionResolver - Resolver instance for determining client permissions
46
+ * @returns Enhanced bundle creation function that accepts client context
47
+ */
48
+ export declare function createPermissionAwareBundle(originalCreateBundle: (allowedToolsets: string[]) => {
49
+ server: McpServer;
50
+ orchestrator: ServerOrchestrator;
51
+ }, permissionResolver: PermissionResolver): (context: ClientRequestContext) => Promise<PermissionAwareBundle>;
52
+ //# sourceMappingURL=createPermissionAwareBundle.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createPermissionAwareBundle.d.ts","sourceRoot":"","sources":["../../src/permissions/createPermissionAwareBundle.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AACxE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAElE;;;GAGG;AACH,MAAM,WAAW,oBAAoB;IACnC;;;OAGG;IACH,QAAQ,EAAE,MAAM,CAAC;IAEjB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAED;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC;;OAEG;IACH,MAAM,EAAE,SAAS,CAAC;IAElB;;OAEG;IACH,YAAY,EAAE,kBAAkB,CAAC;IAEjC;;OAEG;IACH,eAAe,EAAE,MAAM,EAAE,CAAC;CAC3B;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,2BAA2B,CACzC,oBAAoB,EAAE,CAAC,eAAe,EAAE,MAAM,EAAE,KAAK;IACnD,MAAM,EAAE,SAAS,CAAC;IAClB,YAAY,EAAE,kBAAkB,CAAC;CAClC,EACD,kBAAkB,EAAE,kBAAkB,IAYxB,SAAS,oBAAoB,KAAG,OAAO,CAAC,qBAAqB,CAAC,CAwB7E"}
@@ -0,0 +1,9 @@
1
+ import { PermissionConfig } from '../types/index.js';
2
+ /**
3
+ * Validates a permission configuration object to ensure it meets all requirements.
4
+ * Throws descriptive errors for any validation failures.
5
+ * @param config - The permission configuration to validate
6
+ * @throws {Error} If the configuration is invalid or missing required fields
7
+ */
8
+ export declare function validatePermissionConfig(config: PermissionConfig): void;
9
+ //# sourceMappingURL=validatePermissionConfig.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validatePermissionConfig.d.ts","sourceRoot":"","sources":["../../src/permissions/validatePermissionConfig.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAE1D;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,gBAAgB,GAAG,IAAI,CAKvE"}