toolception 0.6.2 → 0.6.3

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/mode.types.ts","../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/http.utils.ts","../src/http/FastifyTransport.ts","../src/session/SessionContextResolver.ts","../src/session/session.utils.ts","../src/server/server.utils.ts","../src/server/createMcpServer.ts","../src/permissions/permissions.utils.ts","../src/permissions/PermissionResolver.ts","../src/permissions/PermissionAwareFastifyTransport.ts","../src/server/createPermissionBasedMcpServer.ts"],"sourcesContent":["import type { ToolSetCatalog, ModuleLoader } from \"../types/index.js\";\n\nexport interface ModeResolverKeys {\n dynamic?: string[];\n toolsets?: string[];\n}\n\nexport interface ModeResolverOptions {\n keys?: ModeResolverKeys;\n}\n\nexport const 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 const RESERVED_TOOLSET_KEYS = [\"_meta\"];\n\nexport interface ModuleResolverOptions {\n catalog: ToolSetCatalog;\n moduleLoaders?: Record<string, ModuleLoader>;\n}\n","import type { Mode, ToolSetCatalog } from \"../types/index.js\";\nimport type { ModeResolverKeys, ModeResolverOptions } from \"./mode.types.js\";\nimport { DEFAULT_KEYS } from \"./mode.types.js\";\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 static builder() {\n const opts: ModeResolverOptions = {};\n const builder = {\n keys(value: ModeResolverKeys) { opts.keys = value; return builder; },\n build() { return new ToolsetValidator(opts); },\n };\n return builder;\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 this.createInvalidNameError(name, catalog);\n }\n const sanitized = name.trim();\n if (sanitized.length === 0) {\n return this.createInvalidNameError(sanitized, catalog);\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 /**\n * @param name - The invalid name value\n * @param catalog - The toolset catalog for listing available options\n * @returns Validation result with descriptive error message\n */\n private createInvalidNameError(\n name: unknown,\n catalog: ToolSetCatalog\n ): { isValid: false; error: string } {\n const available = Object.keys(catalog).join(\", \");\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: ${available}`,\n };\n }\n return {\n isValid: false,\n error: `Empty toolset name provided. Available toolsets: ${available}`,\n };\n }\n\n /**\n * @param toolsetNames - Array of toolset names to validate\n * @param catalog - The toolset catalog to validate against\n * @returns Validation result with modules array if valid\n */\n public validateToolsetModules(\n toolsetNames: string[],\n catalog: ToolSetCatalog\n ): { isValid: boolean; modules?: string[]; error?: string } {\n try {\n // Verify all toolset names exist in catalog first\n for (const name of toolsetNames) {\n if (!catalog[name]) {\n return {\n isValid: false,\n error: `Toolset '${name}' not found in catalog`,\n };\n }\n }\n\n // Get modules - empty array is valid (toolset may have only direct tools)\n const modules = this.getModulesForToolSets(toolsetNames, catalog);\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\";\nimport type { ModuleResolverOptions } from \"./mode.types.js\";\nimport { RESERVED_TOOLSET_KEYS } from \"./mode.types.js\";\n\nexport class ModuleResolver {\n private readonly catalog: ToolSetCatalog;\n private readonly moduleLoaders: Record<string, ModuleLoader>;\n\n constructor(options: ModuleResolverOptions) {\n // Validate catalog doesn't use reserved keys\n for (const key of RESERVED_TOOLSET_KEYS) {\n if (key in options.catalog) {\n throw new Error(\n `Toolset key '${key}' is reserved for internal use and cannot be used in the catalog`\n );\n }\n }\n this.catalog = options.catalog;\n this.moduleLoaders = options.moduleLoaders ?? {};\n }\n\n static builder() {\n const opts: Partial<ModuleResolverOptions> = {};\n const builder = {\n catalog(value: ToolSetCatalog) { opts.catalog = value; return builder; },\n moduleLoaders(value: Record<string, ModuleLoader>) { opts.moduleLoaders = value; return builder; },\n build() { return new ModuleResolver(opts as ModuleResolverOptions); },\n };\n return builder;\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 // Check for reserved keys (defense in depth)\n if (RESERVED_TOOLSET_KEYS.includes(sanitized)) {\n return {\n isValid: false,\n error: `Toolset key '${sanitized}' is reserved for internal use`,\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 this.collectDirectTools(def, collected);\n await this.loadModuleTools(def, name, context, collected);\n }\n return collected;\n }\n\n /**\n * @param def - The toolset definition\n * @param collected - Mutable array to append direct tools to\n */\n private collectDirectTools(\n def: ToolSetDefinition,\n collected: McpToolDefinition[]\n ): void {\n if (Array.isArray(def.tools) && def.tools.length > 0) {\n collected.push(...def.tools);\n }\n }\n\n /**\n * @param def - The toolset definition containing module keys\n * @param toolsetName - The toolset name for error messages\n * @param context - Optional context passed to module loaders\n * @param collected - Mutable array to append loaded tools to\n */\n private async loadModuleTools(\n def: ToolSetDefinition,\n toolsetName: string,\n context: unknown,\n collected: McpToolDefinition[]\n ): Promise<void> {\n if (!Array.isArray(def.modules) || def.modules.length === 0) return;\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 '${toolsetName}':`,\n err\n );\n }\n }\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\";\nimport type { ToolRegistryOptions } from \"./core.types.js\";\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 static builder() {\n const opts: ToolRegistryOptions = {};\n const builder = {\n namespaceWithToolset(value: boolean) { opts.namespaceWithToolset = value; return builder; },\n build() { return new ToolRegistry(opts); },\n };\n return builder;\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\";\nimport type { DynamicToolManagerOptions } from \"./core.types.js\";\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 ?? ToolRegistry.builder().namespaceWithToolset(true).build();\n }\n\n static builder() {\n const opts: Partial<DynamicToolManagerOptions> = {};\n const builder = {\n server(value: McpServer) { opts.server = value; return builder; },\n resolver(value: ModuleResolver) { opts.resolver = value; return builder; },\n context(value: unknown) { opts.context = value; return builder; },\n onToolsListChanged(value: () => Promise<void> | void) { opts.onToolsListChanged = value; return builder; },\n exposurePolicy(value: ExposurePolicy) { opts.exposurePolicy = value; return builder; },\n toolRegistry(value: ToolRegistry) { opts.toolRegistry = value; return builder; },\n build() { return new DynamicToolManager(opts as DynamicToolManagerOptions); },\n };\n return builder;\n }\n\n /**\n * @returns Promise that resolves when notification is sent (or skipped)\n */\n private async notifyToolsChanged(): Promise<void> {\n if (!this.onToolsListChanged) return;\n try {\n await this.onToolsListChanged();\n } catch (err) {\n console.warn(\"Failed to send tool list change notification:\", err);\n }\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 /**\n * Enables a single toolset by name.\n * @param toolsetName - The name of the toolset to enable\n * @param skipNotification - If true, skips the tool list change notification\n * @returns Result object with success status and message\n */\n public async enableToolset(\n toolsetName: string,\n skipNotification = false\n ): Promise<{ success: boolean; message: string }> {\n const validation = this.validateToolsetForEnable(toolsetName);\n if (\"message\" in validation) return validation;\n\n const { sanitized } = validation;\n\n // Check exposure policies BEFORE resolving tools to fail fast\n const policyCheck = this.checkExposurePolicy(sanitized);\n if (!policyCheck.allowed) {\n return { success: false, message: policyCheck.message };\n }\n\n // Track tools registered for this enable operation to allow rollback\n const registeredTools: string[] = [];\n\n try {\n const toolCount = await this.resolveAndRegisterTools(sanitized, registeredTools);\n\n // Track state only after successful registration\n this.activeToolsets.add(sanitized);\n\n // Notify list change (unless skipped for batch operations)\n if (!skipNotification) {\n await this.notifyToolsChanged();\n }\n\n return this.buildEnableResult(sanitized, toolCount);\n } catch (error) {\n this.handlePartialFailure(sanitized, registeredTools);\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 /**\n * @param toolsetName - The raw toolset name to validate\n * @returns Error result if invalid, or `{ sanitized }` to continue\n */\n private validateToolsetForEnable(\n toolsetName: string\n ): { success: boolean; message: string } | { sanitized: 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 if (this.activeToolsets.has(validation.sanitized)) {\n return {\n success: false,\n message: `Toolset '${validation.sanitized}' is already enabled.`,\n };\n }\n return { sanitized: validation.sanitized };\n }\n\n /**\n * @param sanitized - The validated toolset name\n * @param registeredTools - Mutable array tracking registered tool names for rollback\n * @returns The number of tools resolved\n */\n private async resolveAndRegisterTools(\n sanitized: string,\n registeredTools: string[]\n ): Promise<number> {\n const resolvedTools = await this.resolver.resolveToolsForToolsets(\n [sanitized],\n this.context\n );\n\n if (resolvedTools && resolvedTools.length > 0) {\n const mapped = this.toolRegistry.mapAndValidate(sanitized, resolvedTools);\n for (const tool of mapped) {\n this.registerSingleTool(tool, sanitized);\n registeredTools.push(tool.name);\n }\n }\n\n return resolvedTools?.length ?? 0;\n }\n\n /**\n * @param sanitized - The toolset name\n * @param toolCount - Number of tools registered\n * @returns Success result object\n */\n private buildEnableResult(\n sanitized: string,\n toolCount: number\n ): { success: boolean; message: string } {\n return {\n success: true,\n message: `Toolset '${sanitized}' enabled successfully. Registered ${toolCount} tools.`,\n };\n }\n\n /**\n * @param sanitized - The toolset name that partially failed\n * @param registeredTools - Tools that were registered before the failure\n */\n private handlePartialFailure(\n sanitized: string,\n registeredTools: string[]\n ): void {\n if (registeredTools.length > 0) {\n console.warn(\n `Partial failure enabling toolset '${sanitized}'. ` +\n `${registeredTools.length} tools were registered but toolset activation failed. ` +\n `Tools remain registered due to MCP limitations: ${registeredTools.join(\", \")}`\n );\n }\n }\n\n /**\n * @param toolsetName - The sanitized toolset name to check\n * @returns Object indicating if allowed and reason message if not\n */\n private checkExposurePolicy(toolsetName: string): {\n allowed: boolean;\n message: string;\n } {\n if (\n this.exposurePolicy?.allowlist &&\n !this.exposurePolicy.allowlist.includes(toolsetName)\n ) {\n return {\n allowed: false,\n message: `Toolset '${toolsetName}' is not allowed by policy.`,\n };\n }\n if (\n this.exposurePolicy?.denylist &&\n this.exposurePolicy.denylist.includes(toolsetName)\n ) {\n return {\n allowed: false,\n message: `Toolset '${toolsetName}' 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 [toolsetName],\n Array.from(this.activeToolsets)\n );\n return {\n allowed: false,\n message: `Activation exceeds maxActiveToolsets (${this.exposurePolicy.maxActiveToolsets}).`,\n };\n }\n }\n return { allowed: true, message: \"\" };\n }\n\n /**\n * @param tool - The tool definition to register\n * @param toolsetKey - The toolset key for tracking\n */\n private registerSingleTool(tool: McpToolDefinition, toolsetKey: string): void {\n // Only pass annotations if they exist and are not empty\n const hasAnnotations =\n tool.annotations && Object.keys(tool.annotations).length > 0;\n\n if (hasAnnotations && tool.annotations) {\n this.server.tool(\n tool.name,\n tool.description,\n tool.inputSchema as Parameters<typeof this.server.tool>[2],\n tool.annotations,\n async (args: Record<string, unknown>) => {\n return await tool.handler(args);\n }\n );\n } else {\n // Legacy 4-parameter call when no annotations\n this.server.tool(\n tool.name,\n tool.description,\n tool.inputSchema as Parameters<typeof this.server.tool>[2],\n async (args: Record<string, unknown>) => {\n return await tool.handler(args);\n }\n );\n }\n this.toolRegistry.addForToolset(toolsetKey, tool.name);\n }\n\n /**\n * @param toolsetName - The name of the toolset to disable\n * @returns Result object with success status and message\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 await this.notifyToolsChanged();\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 /**\n * @param toolsetNames - Array of toolset names to enable\n * @returns Result object with overall success status and individual results\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\n // Enable each toolset, skipping individual notifications\n for (const name of toolsetNames) {\n try {\n const res = await this.enableToolset(name, true);\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\n const successAll = results.every((r) => r.success);\n const anySuccess = results.some((r) => r.success);\n const message = successAll\n ? \"All toolsets enabled\"\n : anySuccess\n ? \"Some toolsets failed to enable\"\n : \"All toolsets failed to enable\";\n\n // Send a single notification after batch is complete (if any changes occurred)\n if (anySuccess) {\n await this.notifyToolsChanged();\n }\n\n return { success: successAll, results, message };\n }\n\n /**\n * @returns Result object with overall success status and individual results\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\";\nimport { ToolRegistry } from \"../core/ToolRegistry.js\";\n\n/**\n * Reserved toolset key for meta-tools.\n * Meta-tools are registered under this key to enable collision detection\n * and tracking via the ToolRegistry.\n */\nexport const META_TOOLSET_KEY = \"_meta\";\n\n/**\n * Registers meta-tools on the MCP server for toolset management.\n *\n * In DYNAMIC mode, all meta-tools are registered:\n * - enable_toolset, disable_toolset: For runtime toolset management\n * - list_toolsets, describe_toolset: For toolset discovery\n * - list_tools: For listing registered tools\n *\n * In STATIC mode, only list_tools is registered since toolsets are fixed at startup.\n *\n * Meta-tools are registered with the ToolRegistry under the reserved \"_meta\" toolset key\n * to enable collision detection with user-defined tools.\n *\n * @param server - The MCP server to register tools on\n * @param manager - The DynamicToolManager instance\n * @param toolRegistry - The ToolRegistry for collision detection\n * @param options - Configuration options including the mode\n */\nexport function registerMetaTools(\n server: McpServer,\n manager: DynamicToolManager,\n toolRegistry: ToolRegistry,\n options?: { mode?: Exclude<Mode, \"ALL\"> }\n): void {\n const mode = options?.mode ?? \"DYNAMIC\";\n\n // Dynamic-mode only tools: enable/disable toolsets at runtime\n if (mode === \"DYNAMIC\") {\n // Register with ToolRegistry for collision detection before server.tool()\n toolRegistry.addForToolset(META_TOOLSET_KEY, \"enable_toolset\");\n server.tool(\n \"enable_toolset\",\n \"Enable a toolset by name\",\n { name: z.string().describe(\"Toolset name\") },\n { destructiveHint: true, idempotentHint: true },\n async (args: { name: string }) => {\n const result = await manager.enableToolset(args.name);\n return {\n content: [{ type: \"text\", text: JSON.stringify(result) }],\n };\n }\n );\n\n toolRegistry.addForToolset(META_TOOLSET_KEY, \"disable_toolset\");\n server.tool(\n \"disable_toolset\",\n \"Disable a toolset by name (state only)\",\n { name: z.string().describe(\"Toolset name\") },\n { destructiveHint: true, idempotentHint: true },\n async (args: { name: string }) => {\n const result = await manager.disableToolset(args.name);\n return {\n content: [{ type: \"text\", text: JSON.stringify(result) }],\n };\n }\n );\n\n toolRegistry.addForToolset(META_TOOLSET_KEY, \"list_toolsets\");\n server.tool(\n \"list_toolsets\",\n \"List available toolsets with active status and definitions\",\n {},\n { readOnlyHint: true, idempotentHint: true },\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 toolRegistry.addForToolset(META_TOOLSET_KEY, \"describe_toolset\");\n server.tool(\n \"describe_toolset\",\n \"Describe a toolset with definition, active status and tools\",\n { name: z.string().describe(\"Toolset name\") },\n { readOnlyHint: true, idempotentHint: true },\n async (args: { name: string }) => {\n const def = manager.getToolsetDefinition(args.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 '${args.name}'` }),\n },\n ],\n };\n }\n const payload = {\n key: args.name,\n active: manager.isActive(args.name),\n definition: {\n name: def.name,\n description: def.description,\n modules: def.modules ?? [],\n decisionCriteria: def.decisionCriteria ?? undefined,\n },\n tools: byToolset[args.name] ?? [],\n };\n return {\n content: [{ type: \"text\", text: JSON.stringify(payload) }],\n };\n }\n );\n }\n\n // list_tools is available in both modes\n toolRegistry.addForToolset(META_TOOLSET_KEY, \"list_tools\");\n server.tool(\n \"list_tools\",\n \"List currently registered tool names (best effort)\",\n {},\n { readOnlyHint: true, idempotentHint: true },\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 {\n ExposurePolicy,\n Mode,\n ModuleLoader,\n ToolSetCatalog,\n} from \"../types/index.js\";\nimport { ToolRegistry } from \"./ToolRegistry.js\";\nimport type { ServerOrchestratorOptions } from \"./core.types.js\";\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 private readonly initPromise: Promise<void>;\n private initError: Error | null = null;\n\n constructor(options: ServerOrchestratorOptions) {\n this.toolsetValidator = ToolsetValidator.builder().build();\n const startup = options.startup ?? {};\n const resolved = this.resolveStartupConfig(startup, options.catalog);\n this.mode = resolved.mode;\n this.resolver = ModuleResolver.builder()\n .catalog(options.catalog)\n .moduleLoaders(options.moduleLoaders ?? {})\n .build();\n const toolRegistry = ToolRegistry.builder()\n .namespaceWithToolset(\n options.exposurePolicy?.namespaceToolsWithSetKey ?? true\n )\n .build();\n const managerBuilder = DynamicToolManager.builder()\n .server(options.server)\n .resolver(this.resolver)\n .context(options.context)\n .toolRegistry(toolRegistry);\n\n if (options.notifyToolsListChanged) {\n managerBuilder.onToolsListChanged(options.notifyToolsListChanged);\n }\n if (options.exposurePolicy) {\n managerBuilder.exposurePolicy(options.exposurePolicy);\n }\n\n this.manager = managerBuilder.build();\n\n // Register meta-tools only if requested (default true)\n if (options.registerMetaTools !== false) {\n registerMetaTools(options.server, this.manager, toolRegistry, { mode: this.mode });\n }\n\n // Startup behavior - store promise for async initialization\n const initial = resolved.toolsets;\n this.initPromise = this.initializeToolsets(initial);\n }\n\n static builder() {\n const opts: Partial<ServerOrchestratorOptions> = {};\n const builder = {\n server(value: McpServer) { opts.server = value; return builder; },\n catalog(value: ToolSetCatalog) { opts.catalog = value; return builder; },\n moduleLoaders(value: Record<string, ModuleLoader>) { opts.moduleLoaders = value; return builder; },\n exposurePolicy(value: ExposurePolicy) { opts.exposurePolicy = value; return builder; },\n context(value: unknown) { opts.context = value; return builder; },\n notifyToolsListChanged(value: () => Promise<void> | void) { opts.notifyToolsListChanged = value; return builder; },\n startup(value: { mode?: Exclude<Mode, \"ALL\">; toolsets?: string[] | \"ALL\" }) { opts.startup = value; return builder; },\n registerMetaTools(value: boolean) { opts.registerMetaTools = value; return builder; },\n build() { return new ServerOrchestrator(opts as ServerOrchestratorOptions); },\n };\n return builder;\n }\n\n /**\n * @param initial - The toolsets to initialize or \"ALL\"\n * @returns Promise that resolves when initialization is complete\n */\n private async initializeToolsets(\n initial: string[] | \"ALL\" | undefined\n ): Promise<void> {\n try {\n if (initial === \"ALL\") {\n await this.manager.enableToolsets(this.resolver.getAvailableToolsets());\n } else if (Array.isArray(initial) && initial.length > 0) {\n await this.manager.enableToolsets(initial);\n }\n } catch (error) {\n this.initError =\n error instanceof Error ? error : new Error(String(error));\n console.error(\"Failed to initialize toolsets:\", this.initError);\n }\n }\n\n public async ensureReady(): Promise<void> {\n await this.initPromise;\n if (this.initError) {\n throw this.initError;\n }\n }\n\n public async isReady(): Promise<boolean> {\n await this.initPromise;\n return this.initError === null;\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 if (startup.mode) {\n return this.resolveExplicitMode(startup.mode, startup.toolsets, catalog);\n }\n return this.inferModeFromToolsets(startup, catalog);\n }\n\n /**\n * @param mode - The explicit mode\n * @param toolsets - Optional toolsets from startup config\n * @param catalog - The toolset catalog to validate against\n * @returns Resolved mode and toolsets\n */\n private resolveExplicitMode(\n mode: Exclude<Mode, \"ALL\">,\n toolsets: string[] | \"ALL\" | undefined,\n catalog: ToolSetCatalog\n ): { mode: Exclude<Mode, \"ALL\">; toolsets?: string[] | \"ALL\" } {\n if (mode === \"DYNAMIC\" && toolsets) {\n console.warn(\"startup.toolsets provided but ignored in DYNAMIC mode\");\n return { mode: \"DYNAMIC\" };\n }\n if (mode === \"STATIC\") {\n if (toolsets === \"ALL\")\n return { mode: \"STATIC\", toolsets: \"ALL\" };\n const names = Array.isArray(toolsets) ? toolsets : [];\n const valid = this.validateAndCollectToolsets(names, catalog);\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 };\n }\n\n /**\n * @param startup - Startup config without an explicit mode\n * @param catalog - The toolset catalog to validate against\n * @returns Inferred mode and toolsets\n */\n private inferModeFromToolsets(\n startup: { toolsets?: string[] | \"ALL\" },\n catalog: ToolSetCatalog\n ): { mode: Exclude<Mode, \"ALL\">; toolsets?: string[] | \"ALL\" } {\n if (startup.toolsets === \"ALL\") return { mode: \"STATIC\", toolsets: \"ALL\" };\n if (Array.isArray(startup.toolsets) && startup.toolsets.length > 0) {\n const valid = this.validateAndCollectToolsets(startup.toolsets, catalog);\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 return { mode: \"DYNAMIC\" };\n }\n\n /**\n * @param names - Array of toolset names to validate\n * @param catalog - The toolset catalog to validate against\n * @returns Array of valid, sanitized toolset names\n */\n private validateAndCollectToolsets(\n names: string[],\n catalog: ToolSetCatalog\n ): string[] {\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 return valid;\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","import type { ClientResourceCacheOptions, Entry } from \"./session.types.js\";\n\nexport class ClientResourceCache<T> {\n private storage = new Map<string, Entry<T>>();\n private maxSize: number;\n private ttlMs: number;\n private onEvict?: (key: string, resource: T) => void | Promise<void>;\n // Use ReturnType<typeof setInterval> for cross-env typings without NodeJS namespace\n private pruneInterval?: ReturnType<typeof setInterval>;\n\n constructor(options: ClientResourceCacheOptions<T> = {}) {\n this.maxSize = options.maxSize ?? 1000;\n this.ttlMs = options.ttlMs ?? 1000 * 60 * 60;\n this.onEvict = options.onEvict;\n const pruneEvery = options.pruneIntervalMs ?? 1000 * 60 * 10;\n this.pruneInterval = setInterval(() => this.pruneExpired(), pruneEvery);\n }\n\n static builder<T>() {\n const opts: ClientResourceCacheOptions<T> = {};\n const builder = {\n maxSize(value: number) { opts.maxSize = value; return builder; },\n ttlMs(value: number) { opts.ttlMs = value; return builder; },\n pruneIntervalMs(value: number) { opts.pruneIntervalMs = value; return builder; },\n onEvict(value: (key: string, resource: T) => void | Promise<void>) { opts.onEvict = value; return builder; },\n build() { return new ClientResourceCache<T>(opts); },\n };\n return builder;\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 /**\n * @param key - The key to remove\n */\n public delete(key: string): void {\n const entry = this.storage.get(key);\n if (entry) {\n this.storage.delete(key);\n this.#callEvictCallback(key, entry.resource);\n }\n }\n\n /**\n * @param clearEntries - If true, also removes all entries and calls onEvict for each\n */\n public stop(clearEntries = false): void {\n if (this.pruneInterval) {\n clearInterval(this.pruneInterval);\n this.pruneInterval = undefined;\n }\n if (clearEntries) {\n this.clear();\n }\n }\n\n public clear(): void {\n // Collect all entries first to avoid modification during iteration\n const entries = Array.from(this.storage.entries());\n this.storage.clear();\n for (const [key, entry] of entries) {\n this.#callEvictCallback(key, entry.resource);\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 const keysToDelete: string[] = [];\n for (const [key, entry] of this.storage.entries()) {\n if (now - entry.lastAccessed > this.ttlMs) {\n keysToDelete.push(key);\n }\n }\n // Delete after iteration to avoid modification during iteration\n for (const key of keysToDelete) {\n this.delete(key);\n }\n }\n\n /**\n * @param key - The key being evicted\n * @param resource - The resource being evicted\n */\n #callEvictCallback(key: string, resource: T): void {\n if (!this.onEvict) return;\n try {\n const result = this.onEvict(key, resource);\n // Handle async callbacks but don't await\n if (result instanceof Promise) {\n result.catch((err) => {\n console.warn(`Error in cache eviction callback for key '${key}':`, err);\n });\n }\n } catch (err) {\n console.warn(`Error in cache eviction callback for key '${key}':`, err);\n }\n }\n}\n","import type { FastifyInstance, FastifyRequest, FastifyReply } from \"fastify\";\nimport { z } from \"zod\";\nimport { randomUUID } from \"node:crypto\";\nimport type {\n CustomEndpointDefinition,\n CustomEndpointRequest,\n EndpointErrorResponse,\n HttpMethod,\n PermissionAwareEndpointHandler,\n PermissionAwareEndpointRequest,\n RegisterCustomEndpointsOptions,\n} from \"./http.types.js\";\n\n// --- defineEndpoint (from customEndpoints.ts) ---\n\n/**\n * Helper function to create type-safe custom endpoints with automatic type inference.\n * Provides better IntelliSense and type checking for endpoint definitions.\n *\n * @template TBody - Zod schema for request body\n * @template TQuery - Zod schema for query parameters\n * @template TParams - Zod schema for path parameters\n * @template TResponse - Zod schema for response\n *\n * @param definition - Endpoint definition with schemas and handler\n * @returns The same endpoint definition with full type inference\n *\n * @example\n * ```typescript\n * import { z } from \"zod\";\n * import { defineEndpoint } from \"toolception\";\n *\n * const getUsersEndpoint = defineEndpoint({\n * method: \"GET\",\n * path: \"/users\",\n * querySchema: z.object({\n * limit: z.coerce.number().int().positive().default(10),\n * role: z.enum([\"admin\", \"user\"]).optional(),\n * }),\n * responseSchema: z.object({\n * users: z.array(z.object({\n * id: z.string(),\n * name: z.string(),\n * })),\n * total: z.number(),\n * }),\n * handler: async (req) => {\n * // req.query is fully typed: { limit: number, role?: \"admin\" | \"user\" }\n * const { limit, role } = req.query;\n *\n * return {\n * users: [{ id: \"1\", name: \"Alice\" }],\n * total: 1,\n * };\n * },\n * });\n * ```\n */\nexport function defineEndpoint<\n TBody extends z.ZodTypeAny = z.ZodNever,\n TQuery extends z.ZodTypeAny = z.ZodNever,\n TParams extends z.ZodTypeAny = z.ZodNever,\n TResponse extends z.ZodTypeAny = z.ZodAny\n>(\n definition: CustomEndpointDefinition<TBody, TQuery, TParams, TResponse>\n): CustomEndpointDefinition<TBody, TQuery, TParams, TResponse> {\n return definition;\n}\n\n// --- definePermissionAwareEndpoint (from customEndpoints.ts) ---\n\n/**\n * Helper function to create permission-aware custom endpoints for permission-based servers.\n * Similar to defineEndpoint but with access to permission context in the handler.\n *\n * @template TBody - Zod schema for request body\n * @template TQuery - Zod schema for query parameters\n * @template TParams - Zod schema for path parameters\n * @template TResponse - Zod schema for response\n *\n * @param definition - Endpoint definition with permission-aware handler\n * @returns Endpoint definition compatible with permission-based servers\n *\n * @example\n * ```typescript\n * import { definePermissionAwareEndpoint } from \"toolception\";\n *\n * const statsEndpoint = definePermissionAwareEndpoint({\n * method: \"GET\",\n * path: \"/my-permissions\",\n * responseSchema: z.object({\n * toolsets: z.array(z.string()),\n * count: z.number(),\n * }),\n * handler: async (req) => {\n * // req.allowedToolsets and req.failedToolsets are available\n * return {\n * toolsets: req.allowedToolsets,\n * count: req.allowedToolsets.length,\n * };\n * },\n * });\n * ```\n */\nexport function definePermissionAwareEndpoint<\n TBody extends z.ZodTypeAny = z.ZodNever,\n TQuery extends z.ZodTypeAny = z.ZodNever,\n TParams extends z.ZodTypeAny = z.ZodNever,\n TResponse extends z.ZodTypeAny = z.ZodAny\n>(definition: {\n method: HttpMethod;\n path: string;\n bodySchema?: TBody;\n querySchema?: TQuery;\n paramsSchema?: TParams;\n responseSchema?: TResponse;\n handler: PermissionAwareEndpointHandler<TBody, TQuery, TParams, TResponse>;\n description?: string;\n}): CustomEndpointDefinition<TBody, TQuery, TParams, TResponse> {\n // Internal conversion: permission-aware handler is compatible with standard handler\n // The permission fields will be injected by the registration logic\n return definition as any;\n}\n\n// --- registerCustomEndpoints (from endpointRegistration.ts) ---\n\n/**\n * Registers custom endpoints on a Fastify instance.\n * Handles Zod validation, error responses, and type-safe request mapping.\n *\n * @param app - Fastify instance to register endpoints on\n * @param basePath - Base path for all endpoints (e.g., \"/\" or \"/api\")\n * @param endpoints - Array of custom endpoint definitions\n * @param options - Optional configuration for endpoint registration\n *\n * @example\n * ```typescript\n * registerCustomEndpoints(app, \"/api\", [\n * defineEndpoint({\n * method: \"GET\",\n * path: \"/users\",\n * querySchema: z.object({ limit: z.coerce.number() }),\n * handler: async (req) => ({ users: [] }),\n * }),\n * ]);\n * ```\n */\nexport function registerCustomEndpoints(\n app: FastifyInstance,\n basePath: string,\n endpoints: CustomEndpointDefinition[],\n options?: RegisterCustomEndpointsOptions\n): void {\n // Built-in MCP paths that should not be overridden\n const reservedPaths = [\"/mcp\", \"/healthz\", \"/tools\", \"/.well-known/mcp-config\"];\n\n for (const endpoint of endpoints) {\n const fullPath = `${basePath}${endpoint.path}`;\n\n // Check for path conflicts with built-in endpoints\n const isReserved = reservedPaths.some((reserved) =>\n fullPath.startsWith(`${basePath}${reserved}`)\n );\n\n if (isReserved) {\n console.warn(\n `Custom endpoint ${endpoint.method} ${endpoint.path} conflicts with built-in MCP endpoint. Skipping registration.`\n );\n continue;\n }\n\n // Convert method to lowercase for Fastify\n const method = endpoint.method.toLowerCase() as\n | \"get\"\n | \"post\"\n | \"put\"\n | \"delete\"\n | \"patch\";\n\n // Register the endpoint with Fastify\n app[method](fullPath, async (req: FastifyRequest, reply: FastifyReply) => {\n try {\n // Extract client ID from header or generate anonymous ID\n const clientIdHeader = (req.headers[\"mcp-client-id\"] as string)?.trim();\n const clientId =\n clientIdHeader && clientIdHeader.length > 0\n ? clientIdHeader\n : `anon-${randomUUID()}`;\n\n // Validate request body if schema provided\n let body: any = undefined;\n if (endpoint.bodySchema) {\n const bodyResult = endpoint.bodySchema.safeParse(req.body);\n if (!bodyResult.success) {\n return createValidationError(reply, \"body\", bodyResult.error);\n }\n body = bodyResult.data;\n }\n\n // Validate query parameters if schema provided\n let query: any = {};\n if (endpoint.querySchema) {\n const queryResult = endpoint.querySchema.safeParse(req.query);\n if (!queryResult.success) {\n return createValidationError(reply, \"query\", queryResult.error);\n }\n query = queryResult.data;\n }\n\n // Validate path parameters if schema provided\n let params: any = {};\n if (endpoint.paramsSchema) {\n const paramsResult = endpoint.paramsSchema.safeParse(req.params);\n if (!paramsResult.success) {\n return createValidationError(reply, \"params\", paramsResult.error);\n }\n params = paramsResult.data;\n }\n\n // Build request object with validated data\n const customRequest: CustomEndpointRequest = {\n body,\n query,\n params,\n headers: req.headers as Record<string, string | string[] | undefined>,\n clientId,\n };\n\n // Merge additional context if provided (e.g., permissions from contextExtractor)\n if (options?.contextExtractor) {\n const additionalContext = await options.contextExtractor(req);\n Object.assign(customRequest, additionalContext);\n }\n\n // Call the user-defined handler with validated and typed data\n const result = await endpoint.handler(customRequest as any);\n\n // Validate response if schema provided\n if (endpoint.responseSchema) {\n const responseResult = endpoint.responseSchema.safeParse(result);\n if (!responseResult.success) {\n // Log the validation error for debugging\n console.error(\n `Response validation failed for ${endpoint.method} ${endpoint.path}:`,\n responseResult.error\n );\n\n // Return generic error to prevent information leakage\n reply.code(500);\n return {\n error: {\n code: \"RESPONSE_VALIDATION_ERROR\",\n message: \"Internal server error: invalid response format\",\n },\n } as EndpointErrorResponse;\n }\n // Return validated response data\n return responseResult.data;\n }\n\n // No response validation - return result as-is\n return result;\n } catch (error) {\n // Handle any errors thrown by the handler\n console.error(\n `Error in custom endpoint ${endpoint.method} ${endpoint.path}:`,\n error\n );\n\n reply.code(500);\n return {\n error: {\n code: \"INTERNAL_ERROR\",\n message:\n error instanceof Error ? error.message : \"Internal server error\",\n },\n } as EndpointErrorResponse;\n }\n });\n }\n}\n\n/**\n * Creates a standardized validation error response.\n * @param reply - Fastify reply object\n * @param field - The field that failed validation\n * @param error - Zod validation error\n * @returns Formatted error response\n */\nexport function createValidationError(\n reply: FastifyReply,\n field: string,\n error: z.ZodError\n): EndpointErrorResponse {\n reply.code(400);\n return {\n error: {\n code: \"VALIDATION_ERROR\",\n message: `Validation failed for ${field}`,\n details: error.errors,\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 { z } from \"zod\";\nimport type { DynamicToolManager } from \"../core/DynamicToolManager.js\";\nimport type { ServerOrchestrator } from \"../core/ServerOrchestrator.js\";\nimport { ClientResourceCache } from \"../session/ClientResourceCache.js\";\nimport type { SessionContextResolver } from \"../session/SessionContextResolver.js\";\nimport type { SessionRequestContext } from \"../types/index.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 {\n FastifyTransportOptions,\n CreateBundleCallback,\n CustomEndpointDefinition,\n} from \"./http.types.js\";\nimport { registerCustomEndpoints } from \"./http.utils.js\";\n\nconst mcpClientIdSchema = z\n .string({ message: \"Missing required mcp-client-id header\" })\n .trim()\n .min(1, \"mcp-client-id header must not be empty\");\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 customEndpoints?: CustomEndpointDefinition[];\n };\n private readonly defaultManager: DynamicToolManager;\n private readonly createBundle: CreateBundleCallback;\n private readonly sessionContextResolver?: SessionContextResolver;\n private readonly baseContext?: unknown;\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 onEvict: (_key, bundle) => {\n // Clean up all sessions when a client bundle is evicted\n this.cleanupBundle(bundle);\n },\n });\n\n constructor(\n defaultManager: DynamicToolManager,\n createBundle: CreateBundleCallback,\n options: FastifyTransportOptions = {},\n configSchema?: object,\n sessionContextResolver?: SessionContextResolver,\n baseContext?: unknown\n ) {\n this.defaultManager = defaultManager;\n this.createBundle = createBundle;\n this.sessionContextResolver = sessionContextResolver;\n this.baseContext = baseContext;\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 customEndpoints: options.customEndpoints,\n };\n this.configSchema = configSchema;\n }\n\n static builder() {\n let _defaultManager: DynamicToolManager;\n let _createBundle: CreateBundleCallback;\n const opts: FastifyTransportOptions = {};\n let _configSchema: object | undefined;\n let _sessionContextResolver: SessionContextResolver | undefined;\n let _baseContext: unknown;\n const builder = {\n defaultManager(value: DynamicToolManager) { _defaultManager = value; return builder; },\n createBundle(value: CreateBundleCallback) { _createBundle = value; return builder; },\n host(value: string) { opts.host = value; return builder; },\n port(value: number) { opts.port = value; return builder; },\n basePath(value: string) { opts.basePath = value; return builder; },\n cors(value: boolean) { opts.cors = value; return builder; },\n logger(value: boolean) { opts.logger = value; return builder; },\n app(value: FastifyInstance) { opts.app = value; return builder; },\n customEndpoints(value: CustomEndpointDefinition[]) { opts.customEndpoints = value; return builder; },\n configSchema(value: object) { _configSchema = value; return builder; },\n sessionContextResolver(value: SessionContextResolver) { _sessionContextResolver = value; return builder; },\n baseContext(value: unknown) { _baseContext = value; return builder; },\n build() { return new FastifyTransport(_defaultManager, _createBundle, opts, _configSchema, _sessionContextResolver, _baseContext); },\n };\n return builder;\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.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 // Register custom endpoints if provided\n if (this.options.customEndpoints && this.options.customEndpoints.length > 0) {\n registerCustomEndpoints(app, base, this.options.customEndpoints);\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 /**\n * @param basePath - The base path to normalize\n * @returns Normalized base path without trailing slash\n */\n private normalizeBasePath(basePath: string): string {\n return basePath.endsWith(\"/\") ? basePath.slice(0, -1) : basePath;\n }\n\n /**\n * @param app - Fastify instance\n * @param base - Base path for routes\n */\n private registerHealthEndpoint(app: FastifyInstance, base: string): void {\n app.get(`${base}/healthz`, async () => ({ ok: true }));\n }\n\n /**\n * @param app - Fastify instance\n * @param base - Base path for routes\n */\n private registerToolsEndpoint(app: FastifyInstance, base: string): void {\n app.get(`${base}/tools`, async () => this.defaultManager.getStatus());\n }\n\n /**\n * @param app - Fastify instance\n * @param base - Base path for routes\n */\n private 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 * @param app - Fastify instance\n * @param base - Base path for routes\n */\n private registerMcpPostEndpoint(app: FastifyInstance, base: string): void {\n app.post(\n `${base}/mcp`,\n async (req: FastifyRequest, reply: FastifyReply) => {\n const parseResult = mcpClientIdSchema.safeParse(\n req.headers[\"mcp-client-id\"]\n );\n if (!parseResult.success) {\n reply.code(400);\n return {\n jsonrpc: \"2.0\",\n error: { code: -32600, message: parseResult.error.issues[0].message },\n id: null,\n };\n }\n const clientId = parseResult.data;\n\n // Build session request context and resolve merged context\n const { cacheKey, mergedContext } = this.resolveSessionContext(\n req,\n clientId\n );\n\n let bundle = this.clientCache.get(cacheKey);\n if (!bundle) {\n const created = this.createBundle(mergedContext);\n bundle = {\n server: created.server,\n orchestrator: created.orchestrator,\n sessions: new Map(),\n };\n this.clientCache.set(cacheKey, 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\n /**\n * @param app - Fastify instance\n * @param base - Base path for routes\n */\n private 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 { cacheKey } = this.resolveSessionContext(req, clientId);\n const bundle = this.clientCache.get(cacheKey);\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 * @param app - Fastify instance\n * @param base - Base path for routes\n */\n private 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 { cacheKey } = this.resolveSessionContext(req, clientId);\n const bundle = this.clientCache.get(cacheKey);\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 public async stop(): Promise<void> {\n if (!this.app) return;\n\n // Stop the cache pruning interval and clear all entries (triggers cleanup)\n this.clientCache.stop(true);\n\n if (!this.options.app) {\n await this.app.close();\n }\n this.app = null;\n }\n\n /**\n * @param bundle - The client bundle to clean up\n */\n private cleanupBundle(bundle: {\n server: McpServer;\n orchestrator: ServerOrchestrator;\n sessions: Map<string, StreamableHTTPServerTransport>;\n }): void {\n for (const [sessionId, transport] of bundle.sessions.entries()) {\n try {\n if (typeof (transport as any).close === \"function\") {\n (transport as any).close().catch((err: unknown) => {\n console.warn(`Error closing session ${sessionId}:`, err);\n });\n }\n } catch (err) {\n console.warn(`Error closing session ${sessionId}:`, err);\n }\n }\n bundle.sessions.clear();\n }\n\n /**\n * @param req - The Fastify request\n * @param clientId - The client identifier\n * @returns Object with cache key and merged context\n */\n private resolveSessionContext(\n req: FastifyRequest,\n clientId: string\n ): { cacheKey: string; mergedContext: unknown } {\n // If no session context resolver, use simple clientId cache key\n if (!this.sessionContextResolver) {\n return {\n cacheKey: clientId,\n mergedContext: this.baseContext,\n };\n }\n\n // Build session request context\n const sessionRequestContext: SessionRequestContext = {\n clientId,\n headers: this.extractHeaders(req),\n query: this.extractQuery(req),\n };\n\n // Resolve the merged context\n const result = this.sessionContextResolver.resolve(\n sessionRequestContext,\n this.baseContext\n );\n\n // Build cache key: clientId:suffix\n const cacheKey =\n result.cacheKeySuffix === \"default\"\n ? clientId\n : `${clientId}:${result.cacheKeySuffix}`;\n\n return {\n cacheKey,\n mergedContext: result.context,\n };\n }\n\n /**\n * @param req - The Fastify request\n * @returns Headers as a string record\n */\n private extractHeaders(req: FastifyRequest): Record<string, string> {\n const headers: Record<string, string> = {};\n for (const [key, value] of Object.entries(req.headers)) {\n if (typeof value === \"string\") {\n headers[key.toLowerCase()] = value;\n } else if (Array.isArray(value) && value.length > 0) {\n headers[key.toLowerCase()] = value[0];\n }\n }\n return headers;\n }\n\n /**\n * @param req - The Fastify request\n * @returns Query parameters as a string record\n */\n private extractQuery(req: FastifyRequest): Record<string, string> {\n const query: Record<string, string> = {};\n const rawQuery = req.query as Record<string, unknown>;\n if (rawQuery && typeof rawQuery === \"object\") {\n for (const [key, value] of Object.entries(rawQuery)) {\n if (typeof value === \"string\") {\n query[key] = value;\n }\n }\n }\n return query;\n }\n}\n","import type {\n SessionContextConfig,\n SessionRequestContext,\n} from \"../types/index.js\";\nimport { createHash } from \"node:crypto\";\nimport type { SessionContextResult } from \"./session.types.js\";\n\nexport class SessionContextResolver {\n private readonly config: SessionContextConfig;\n private readonly queryParamName: string;\n private readonly encoding: \"base64\" | \"json\";\n private readonly allowedKeys: Set<string> | null;\n private readonly mergeStrategy: \"shallow\" | \"deep\";\n\n constructor(config: SessionContextConfig) {\n this.config = config;\n this.queryParamName = config.queryParam?.name ?? \"config\";\n this.encoding = config.queryParam?.encoding ?? \"base64\";\n this.allowedKeys = config.queryParam?.allowedKeys\n ? new Set(config.queryParam.allowedKeys)\n : null;\n this.mergeStrategy = config.merge ?? \"shallow\";\n }\n\n static builder() {\n const opts: Partial<SessionContextConfig> = {};\n const builder = {\n enabled(value: boolean) { opts.enabled = value; return builder; },\n queryParam(value: SessionContextConfig[\"queryParam\"]) { opts.queryParam = value; return builder; },\n contextResolver(value: SessionContextConfig[\"contextResolver\"]) { opts.contextResolver = value; return builder; },\n merge(value: \"shallow\" | \"deep\") { opts.merge = value; return builder; },\n build() { return new SessionContextResolver(opts as SessionContextConfig); },\n };\n return builder;\n }\n\n /**\n * @param request - The request context (clientId, headers, query)\n * @param baseContext - The base context from server configuration\n * @returns The resolved context and cache key suffix\n */\n resolve(\n request: SessionRequestContext,\n baseContext: unknown\n ): SessionContextResult {\n // If disabled, return base context with default cache key\n if (this.config.enabled === false) {\n return {\n context: baseContext,\n cacheKeySuffix: \"default\",\n };\n }\n\n const parsedConfig = this.parseQueryConfig(request.query);\n\n if (this.config.contextResolver) {\n return this.resolveWithCustomResolver(request, baseContext, parsedConfig);\n }\n\n return this.resolveWithDefaultMerge(baseContext, parsedConfig);\n }\n\n /**\n * @param request - The request context\n * @param baseContext - The base context from server configuration\n * @param parsedConfig - The parsed query parameter config\n * @returns The resolved context and cache key suffix\n */\n private resolveWithCustomResolver(\n request: SessionRequestContext,\n baseContext: unknown,\n parsedConfig: Record<string, unknown>\n ): SessionContextResult {\n const resolver = this.config.contextResolver;\n if (!resolver) {\n return { context: baseContext, cacheKeySuffix: \"default\" };\n }\n\n try {\n const resolvedContext = resolver(\n request,\n baseContext,\n parsedConfig\n );\n return {\n context: resolvedContext,\n cacheKeySuffix: this.generateCacheKeySuffix(parsedConfig),\n };\n } catch {\n // Fail secure: return base context on resolver error\n return {\n context: baseContext,\n cacheKeySuffix: \"default\",\n };\n }\n }\n\n /**\n * @param baseContext - The base context from server configuration\n * @param parsedConfig - The parsed query parameter config\n * @returns The merged context and cache key suffix\n */\n private resolveWithDefaultMerge(\n baseContext: unknown,\n parsedConfig: Record<string, unknown>\n ): SessionContextResult {\n const mergedContext = this.mergeContexts(baseContext, parsedConfig);\n return {\n context: mergedContext,\n cacheKeySuffix: this.generateCacheKeySuffix(parsedConfig),\n };\n }\n\n /**\n * @param query - Query parameters from the request\n * @returns Parsed and filtered config object\n */\n private parseQueryConfig(\n query: Record<string, string>\n ): Record<string, unknown> {\n const rawValue = query[this.queryParamName];\n if (!rawValue) {\n return {};\n }\n\n try {\n let jsonString: string;\n\n if (this.encoding === \"base64\") {\n // Decode base64 to JSON string\n jsonString = Buffer.from(rawValue, \"base64\").toString(\"utf-8\");\n } else {\n // JSON encoding - value should already be JSON string\n jsonString = rawValue;\n }\n\n const parsed = JSON.parse(jsonString);\n\n // Must be an object\n if (typeof parsed !== \"object\" || parsed === null || Array.isArray(parsed)) {\n return {};\n }\n\n // Filter allowed keys if whitelist is configured\n return this.filterAllowedKeys(parsed);\n } catch {\n // Fail secure: return empty object on any parse error\n return {};\n }\n }\n\n /**\n * @param parsed - The parsed config object\n * @returns Filtered config with only allowed keys\n */\n private filterAllowedKeys(\n parsed: Record<string, unknown>\n ): Record<string, unknown> {\n if (!this.allowedKeys) {\n return parsed;\n }\n\n const filtered: Record<string, unknown> = {};\n for (const key of this.allowedKeys) {\n if (key in parsed) {\n filtered[key] = parsed[key];\n }\n }\n return filtered;\n }\n\n /**\n * @param baseContext - The base context from server configuration\n * @param sessionConfig - The parsed session config\n * @returns Merged context\n */\n private mergeContexts(\n baseContext: unknown,\n sessionConfig: Record<string, unknown>\n ): unknown {\n // If no session config, return base context as-is\n if (Object.keys(sessionConfig).length === 0) {\n return baseContext;\n }\n\n // If base context is not an object, session config takes precedence\n if (\n typeof baseContext !== \"object\" ||\n baseContext === null ||\n Array.isArray(baseContext)\n ) {\n return sessionConfig;\n }\n\n if (this.mergeStrategy === \"deep\") {\n return this.deepMerge(\n baseContext as Record<string, unknown>,\n sessionConfig\n );\n }\n\n // Shallow merge: session config overrides base context\n return {\n ...(baseContext as Record<string, unknown>),\n ...sessionConfig,\n };\n }\n\n /**\n * @param base - The base object\n * @param override - The override object\n * @returns Deep merged object\n */\n private deepMerge(\n base: Record<string, unknown>,\n override: Record<string, unknown>\n ): Record<string, unknown> {\n const result: Record<string, unknown> = { ...base };\n\n for (const [key, value] of Object.entries(override)) {\n const baseValue = result[key];\n\n if (\n typeof value === \"object\" &&\n value !== null &&\n !Array.isArray(value) &&\n typeof baseValue === \"object\" &&\n baseValue !== null &&\n !Array.isArray(baseValue)\n ) {\n // Both are objects - deep merge\n result[key] = this.deepMerge(\n baseValue as Record<string, unknown>,\n value as Record<string, unknown>\n );\n } else {\n // Override base value\n result[key] = value;\n }\n }\n\n return result;\n }\n\n /**\n * @param sessionConfig - The parsed session config\n * @returns Hash string or 'default'\n */\n private generateCacheKeySuffix(\n sessionConfig: Record<string, unknown>\n ): string {\n if (Object.keys(sessionConfig).length === 0) {\n return \"default\";\n }\n\n // Sort keys for deterministic hash\n const sortedKeys = Object.keys(sessionConfig).sort();\n const normalizedObj: Record<string, unknown> = {};\n for (const key of sortedKeys) {\n normalizedObj[key] = sessionConfig[key];\n }\n\n const jsonString = JSON.stringify(normalizedObj);\n return createHash(\"sha256\").update(jsonString).digest(\"hex\").slice(0, 16);\n }\n}\n","import type { SessionContextConfig } from \"../types/index.js\";\n\n/**\n * Validates a session context configuration object to ensure it meets all requirements.\n * Throws descriptive errors for any validation failures.\n *\n * @param config - The session context configuration to validate\n */\nexport function validateSessionContextConfig(config: SessionContextConfig): void {\n validateConfigExists(config);\n validateEnabledField(config);\n validateQueryParamConfig(config);\n validateContextResolver(config);\n validateMergeStrategy(config);\n}\n\n/**\n * @param config - The session context configuration to validate\n */\nfunction validateConfigExists(config: SessionContextConfig): void {\n if (!config || typeof config !== \"object\") {\n throw new Error(\n \"Session context configuration must be an object\"\n );\n }\n}\n\n/**\n * @param config - The session context configuration to validate\n */\nfunction validateEnabledField(config: SessionContextConfig): void {\n if (config.enabled === undefined) {\n return;\n }\n\n if (typeof config.enabled !== \"boolean\") {\n throw new Error(\n `enabled must be a boolean, got ${typeof config.enabled}`\n );\n }\n}\n\n/**\n * @param config - The session context configuration to validate\n */\nfunction validateQueryParamConfig(config: SessionContextConfig): void {\n if (config.queryParam === undefined) {\n return;\n }\n\n if (typeof config.queryParam !== \"object\" || config.queryParam === null) {\n throw new Error(\"queryParam must be an object\");\n }\n\n // Validate name\n if (config.queryParam.name !== undefined) {\n if (\n typeof config.queryParam.name !== \"string\" ||\n config.queryParam.name.length === 0\n ) {\n throw new Error(\"queryParam.name must be a non-empty string\");\n }\n }\n\n // Validate encoding\n if (config.queryParam.encoding !== undefined) {\n if (\n config.queryParam.encoding !== \"base64\" &&\n config.queryParam.encoding !== \"json\"\n ) {\n throw new Error(\n `Invalid queryParam.encoding: \"${config.queryParam.encoding}\". Must be \"base64\" or \"json\"`\n );\n }\n }\n\n // Validate allowedKeys\n if (config.queryParam.allowedKeys !== undefined) {\n if (!Array.isArray(config.queryParam.allowedKeys)) {\n throw new Error(\"queryParam.allowedKeys must be an array of strings\");\n }\n\n for (let i = 0; i < config.queryParam.allowedKeys.length; i++) {\n const key = config.queryParam.allowedKeys[i];\n if (typeof key !== \"string\" || key.length === 0) {\n throw new Error(\n `queryParam.allowedKeys[${i}] must be a non-empty string`\n );\n }\n }\n }\n}\n\n/**\n * @param config - The session context configuration to validate\n */\nfunction validateContextResolver(config: SessionContextConfig): void {\n if (config.contextResolver === undefined) {\n return;\n }\n\n if (typeof config.contextResolver !== \"function\") {\n throw new Error(\n \"contextResolver must be a function: (request, baseContext, parsedQueryConfig?) => unknown\"\n );\n }\n}\n\n/**\n * @param config - The session context configuration to validate\n */\nfunction validateMergeStrategy(config: SessionContextConfig): void {\n if (config.merge === undefined) {\n return;\n }\n\n if (config.merge !== \"shallow\" && config.merge !== \"deep\") {\n throw new Error(\n `Invalid merge strategy: \"${config.merge}\". Must be \"shallow\" or \"deep\"`\n );\n }\n}\n","import { z } from \"zod\";\nimport type { Mode } from \"../types/index.js\";\n\n/**\n * Zod schema for validating startup configuration.\n * Uses strict mode to reject unknown properties like 'initialToolsets'.\n */\nexport const startupConfigSchema = z\n .object({\n mode: z.enum([\"DYNAMIC\", \"STATIC\"]).optional(),\n toolsets: z.union([z.array(z.string()), z.literal(\"ALL\")]).optional(),\n })\n .strict();\n\n/**\n * Validates a startup configuration object against `startupConfigSchema`.\n * Throws a descriptive error when the config is invalid.\n *\n * @param startup - The startup configuration to validate\n */\nexport function validateStartupConfig(\n startup: { mode?: Exclude<Mode, \"ALL\">; toolsets?: string[] | \"ALL\" }\n): void {\n try {\n startupConfigSchema.parse(startup);\n } catch (error) {\n if (error instanceof z.ZodError) {\n const formatted = error.format();\n throw new Error(\n `Invalid startup configuration:\\n${JSON.stringify(formatted, null, 2)}\\n\\n` +\n `Hint: Common mistake - use \"toolsets\" not \"initialToolsets\"`\n );\n }\n throw error;\n }\n}\n\n/**\n * Creates a notifier function that sends `tools/list_changed` notifications\n * to an MCP server. Handles two different notification APIs and suppresses\n * \"Not connected\" errors that occur when no clients are connected.\n *\n * @returns A function that sends tools/list_changed notifications to an MCP server\n */\nexport function createToolsChangedNotifier(): (target: unknown) => Promise<void> {\n type NotifierA = {\n server: { notification: (msg: { method: string }) => Promise<void> | void };\n };\n type NotifierB = { notifyToolsListChanged: () => Promise<void> | void };\n\n const hasNotifierA = (s: unknown): s is NotifierA =>\n typeof (s as NotifierA)?.server?.notification === \"function\";\n const hasNotifierB = (s: unknown): s is NotifierB =>\n typeof (s as NotifierB)?.notifyToolsListChanged === \"function\";\n\n return 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 (err) {\n // Suppress \"Not connected\" errors - expected when no clients are connected\n const errorMessage = err instanceof Error ? err.message : String(err);\n if (errorMessage === \"Not connected\") {\n return; // Silently ignore - no clients to notify\n }\n // Log other errors as they indicate actual problems\n console.warn(\"Failed to send tools list changed notification:\", err);\n }\n };\n}\n\n/**\n * Resolves whether meta-tools should be registered.\n * When `explicit` is provided it takes precedence; otherwise meta-tools are\n * enabled in DYNAMIC mode and disabled in STATIC mode.\n *\n * @param explicit - The user-provided registerMetaTools value (undefined = auto)\n * @param mode - The resolved server mode\n * @returns Whether meta-tools should be registered\n */\nexport function resolveMetaToolsFlag(\n explicit: boolean | undefined,\n mode: Exclude<Mode, \"ALL\">\n): boolean {\n return explicit !== undefined ? explicit : mode === \"DYNAMIC\";\n}\n","import type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport type { Mode } from \"../types/index.js\";\nimport type { CreateBundleCallback } from \"../http/http.types.js\";\nimport type { CreateMcpServerOptions, McpServerHandle } from \"./server.types.js\";\nimport { ServerOrchestrator } from \"../core/ServerOrchestrator.js\";\nimport { FastifyTransport } from \"../http/FastifyTransport.js\";\nimport { SessionContextResolver } from \"../session/SessionContextResolver.js\";\nimport { validateSessionContextConfig } from \"../session/session.utils.js\";\nimport {\n validateStartupConfig,\n createToolsChangedNotifier,\n resolveMetaToolsFlag,\n} from \"./server.utils.js\";\n\nexport type { CreateMcpServerOptions } from \"./server.types.js\";\n\nexport async function createMcpServer(\n options: CreateMcpServerOptions\n): Promise<McpServerHandle> {\n // --- Validate ---\n validateOptions(options);\n\n const mode: Exclude<Mode, \"ALL\"> = options.startup?.mode ?? \"DYNAMIC\";\n const shouldRegisterMetaTools = resolveMetaToolsFlag(options.registerMetaTools, mode);\n const sessionContextResolver = buildSessionContextResolver(options, mode);\n const notifyToolsChanged = createToolsChangedNotifier();\n\n // --- Build base server & orchestrator ---\n const baseServer: McpServer = options.createServer();\n const baseOrchestrator = buildOrchestrator(\n baseServer, options, mode, shouldRegisterMetaTools, notifyToolsChanged\n );\n\n if (mode === \"STATIC\") {\n await baseOrchestrator.ensureReady();\n }\n\n // --- Build transport ---\n const bundleFactory = createBundleFactory(\n options, mode, baseServer, baseOrchestrator, shouldRegisterMetaTools, notifyToolsChanged\n );\n const transport = buildTransport(\n options, baseOrchestrator.getManager(), bundleFactory, sessionContextResolver\n );\n\n return {\n server: baseServer,\n start: () => transport.start(),\n close: () => transport.stop(),\n };\n}\n\n// ---------------------------------------------------------------------------\n// Named helper functions\n// ---------------------------------------------------------------------------\n\n/**\n * Consolidates all upfront validation guards.\n *\n * @param options - Server creation options to validate\n */\nfunction validateOptions(options: CreateMcpServerOptions): void {\n if (options.startup) {\n validateStartupConfig(options.startup);\n }\n if (typeof options.createServer !== \"function\") {\n throw new Error(\"createMcpServer: `createServer` (factory) is required\");\n }\n}\n\n/**\n * Validates session context config, builds the resolver, and warns about\n * limited utility in STATIC mode.\n *\n * @param options - Server creation options containing sessionContext config\n * @param mode - The resolved server mode\n * @returns A SessionContextResolver if configured, otherwise undefined\n */\nfunction buildSessionContextResolver(\n options: CreateMcpServerOptions,\n mode: Exclude<Mode, \"ALL\">\n): SessionContextResolver | undefined {\n if (!options.sessionContext) return undefined;\n\n validateSessionContextConfig(options.sessionContext);\n\n const resolver = SessionContextResolver.builder()\n .enabled(options.sessionContext.enabled ?? true)\n .queryParam(options.sessionContext.queryParam)\n .contextResolver(options.sessionContext.contextResolver)\n .merge(options.sessionContext.merge ?? \"shallow\")\n .build();\n\n if (mode === \"STATIC\" && options.sessionContext.enabled !== false) {\n console.warn(\n \"sessionContext has limited effect in STATIC mode: all clients share the same server instance with base context. \" +\n \"Use DYNAMIC mode for per-session context isolation.\"\n );\n }\n\n return resolver;\n}\n\n/**\n * Builds a ServerOrchestrator with the standard configuration. Used once for\n * the base orchestrator and once per DYNAMIC client.\n *\n * @param server - The MCP server instance\n * @param options - Server creation options (catalog, moduleLoaders, exposurePolicy, startup)\n * @param mode - The resolved server mode\n * @param shouldRegisterMetaTools - Pre-resolved meta-tools flag\n * @param notifyToolsChanged - Notifier function for tool list changes\n * @param context - Optional context override (defaults to options.context)\n * @returns A configured ServerOrchestrator\n */\nfunction buildOrchestrator(\n server: McpServer,\n options: CreateMcpServerOptions,\n mode: Exclude<Mode, \"ALL\">,\n shouldRegisterMetaTools: boolean,\n notifyToolsChanged: (target: unknown) => Promise<void>,\n context?: unknown\n): ServerOrchestrator {\n const builder = ServerOrchestrator.builder()\n .server(server)\n .catalog(options.catalog)\n .moduleLoaders(options.moduleLoaders ?? {})\n .context(context !== undefined ? context : options.context)\n .notifyToolsListChanged(async () => notifyToolsChanged(server))\n .registerMetaTools(shouldRegisterMetaTools);\n\n if (options.exposurePolicy) {\n builder.exposurePolicy(options.exposurePolicy);\n }\n if (options.startup) {\n builder.startup(options.startup);\n }\n\n return builder.build();\n}\n\n/**\n * Creates the bundle factory callback for the transport layer.\n * In STATIC mode all clients share one server + orchestrator.\n * In DYNAMIC mode a fresh server + orchestrator is created per client.\n *\n * @param options - Server creation options\n * @param mode - STATIC reuses base bundle; DYNAMIC creates fresh per client\n * @param baseServer - The shared base server instance\n * @param baseOrchestrator - The shared base orchestrator\n * @param shouldRegisterMetaTools - Pre-resolved meta-tools flag\n * @param notifyToolsChanged - Notifier function for tool list changes\n * @returns Bundle factory callback for the transport layer\n */\nfunction createBundleFactory(\n options: CreateMcpServerOptions,\n mode: Exclude<Mode, \"ALL\">,\n baseServer: McpServer,\n baseOrchestrator: ServerOrchestrator,\n shouldRegisterMetaTools: boolean,\n notifyToolsChanged: (target: unknown) => Promise<void>\n): CreateBundleCallback {\n return (mergedContext?: unknown) => {\n if (mode === \"STATIC\") {\n // STATIC: all clients share one server + orchestrator\n return { server: baseServer, orchestrator: baseOrchestrator };\n }\n\n // DYNAMIC: fresh server + orchestrator per client\n const effectiveContext = mergedContext ?? options.context;\n const clientServer: McpServer = options.createServer();\n const clientOrchestrator = buildOrchestrator(\n clientServer, options, mode, shouldRegisterMetaTools, notifyToolsChanged, effectiveContext\n );\n return { server: clientServer, orchestrator: clientOrchestrator };\n };\n}\n\n/**\n * Builds the FastifyTransport using the builder pattern, handling conditional\n * `.app()`, `.customEndpoints()`, `.sessionContextResolver()`, and `.baseContext()` chaining.\n *\n * @param options - Server creation options (http, configSchema, context)\n * @param manager - Default DynamicToolManager for status endpoints\n * @param bundleFactory - Bundle factory callback for the transport layer\n * @param sessionContextResolver - Optional session context resolver\n * @returns A configured FastifyTransport\n */\nfunction buildTransport(\n options: CreateMcpServerOptions,\n manager: ReturnType<ServerOrchestrator[\"getManager\"]>,\n bundleFactory: CreateBundleCallback,\n sessionContextResolver: SessionContextResolver | undefined\n): FastifyTransport {\n const builder = FastifyTransport.builder()\n .defaultManager(manager)\n .createBundle(bundleFactory)\n .host(options.http?.host ?? \"0.0.0.0\")\n .port(options.http?.port ?? 3000)\n .basePath(options.http?.basePath ?? \"/\")\n .cors(options.http?.cors ?? true)\n .logger(options.http?.logger ?? false);\n\n if (options.http?.app) {\n builder.app(options.http.app);\n }\n if (options.http?.customEndpoints) {\n builder.customEndpoints(options.http.customEndpoints);\n }\n if (options.configSchema) {\n builder.configSchema(options.configSchema);\n }\n if (sessionContextResolver) {\n builder.sessionContextResolver(sessionContextResolver);\n }\n if (options.context !== undefined) {\n builder.baseContext(options.context);\n }\n\n return builder.build();\n}\n","import type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport type { ExposurePolicy, PermissionConfig } from \"../types/index.js\";\nimport type { ServerOrchestrator } from \"../core/ServerOrchestrator.js\";\nimport type { PermissionResolver } from \"./PermissionResolver.js\";\nimport type {\n ClientRequestContext,\n PermissionAwareBundle,\n} from \"./permissions.types.js\";\n\n// --- Validation functions (from validatePermissionConfig.ts) ---\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 */\nexport function validatePermissionConfig(config: PermissionConfig): void {\n validateConfigExists(config);\n validateSourceField(config);\n validateConfigBasedPermissions(config);\n validateTypes(config);\n}\n\n/**\n * @param config - The permission configuration to validate\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 * @param config - The permission configuration to validate\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 * @param config - The permission configuration to validate\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 * @param config - The permission configuration to validate\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 * @param staticMap - The static map to validate\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\n// --- createPermissionAwareBundle (from createPermissionAwareBundle.ts) ---\n\n/**\n * Creates a permission-aware bundle creation function that wraps the original\n * createBundle function with permission resolution and enforcement.\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 return async (\n context: ClientRequestContext\n ): Promise<PermissionAwareBundle> => {\n // Resolve permissions for this client\n const requestedToolsets = 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(requestedToolsets);\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\n const enabledToolsets: string[] = [];\n const failedToolsets: string[] = [];\n\n if (requestedToolsets.length > 0) {\n const result = await manager.enableToolsets(requestedToolsets);\n\n // Collect successful and failed toolsets\n for (const r of result.results) {\n if (r.success) {\n enabledToolsets.push(r.name);\n } else {\n failedToolsets.push(r.name);\n console.warn(\n `Failed to enable toolset '${r.name}' for client '${context.clientId}': ${r.message}`\n );\n }\n }\n\n // If ALL toolsets failed, this is likely a configuration error\n if (enabledToolsets.length === 0 && failedToolsets.length > 0) {\n throw new Error(\n `All requested toolsets failed to enable for client '${context.clientId}'. ` +\n `Requested: [${requestedToolsets.join(\", \")}]. ` +\n `Check that toolset names in permissions match the catalog.`\n );\n }\n }\n\n // Return bundle with resolved permissions\n return {\n server: bundle.server,\n orchestrator: bundle.orchestrator,\n allowedToolsets: enabledToolsets,\n failedToolsets,\n };\n };\n}\n\n// --- sanitizeExposurePolicyForPermissions (from createPermissionBasedMcpServer.ts) ---\n\n/**\n * Validates and sanitizes exposure policy for permission-based servers.\n * Certain policy options are not applicable or could conflict with permission-based access control.\n * @param policy - The original exposure policy\n * @returns Sanitized policy safe for permission-based servers\n */\nexport function sanitizeExposurePolicyForPermissions(\n policy?: ExposurePolicy\n): ExposurePolicy | undefined {\n if (!policy) return undefined;\n\n const sanitized: ExposurePolicy = {\n namespaceToolsWithSetKey: policy.namespaceToolsWithSetKey,\n };\n\n // Warn about ignored options\n if (policy.allowlist !== undefined) {\n console.warn(\n \"Permission-based servers: exposurePolicy.allowlist is ignored. \" +\n \"Allowed toolsets are determined by client permissions.\"\n );\n }\n if (policy.denylist !== undefined) {\n console.warn(\n \"Permission-based servers: exposurePolicy.denylist is ignored. \" +\n \"Use permission configuration to control toolset access.\"\n );\n }\n if (policy.maxActiveToolsets !== undefined) {\n console.warn(\n \"Permission-based servers: exposurePolicy.maxActiveToolsets is ignored. \" +\n \"Toolset count is determined by client permissions.\"\n );\n }\n if (policy.onLimitExceeded !== undefined) {\n console.warn(\n \"Permission-based servers: exposurePolicy.onLimitExceeded is ignored. \" +\n \"No toolset limits are enforced.\"\n );\n }\n\n return sanitized;\n}\n","import type { PermissionConfig } from \"../types/index.js\";\n\nexport class PermissionResolver {\n private cache = new Map<string, string[]>();\n private readonly normalizedHeaderName: string;\n\n constructor(private config: PermissionConfig) {\n // Pre-normalize header name to lowercase for case-insensitive matching\n this.normalizedHeaderName = (\n config.headerName || \"mcp-toolset-permissions\"\n ).toLowerCase();\n }\n\n static builder() {\n const opts: Partial<PermissionConfig> = {};\n const builder = {\n source(value: \"headers\" | \"config\") { opts.source = value; return builder; },\n headerName(value: string) { opts.headerName = value; return builder; },\n staticMap(value: Record<string, string[]>) { opts.staticMap = value; return builder; },\n resolver(value: (clientId: string) => string[]) { opts.resolver = value; return builder; },\n defaultPermissions(value: string[]) { opts.defaultPermissions = value; return builder; },\n build() { return new PermissionResolver(opts as PermissionConfig); },\n };\n return builder;\n }\n\n /**\n * @param clientId - The unique identifier for the client\n * @param headers - Optional request headers\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 * @param clientId - The client ID to invalidate\n */\n invalidateCache(clientId: string): void {\n this.cache.delete(clientId);\n }\n\n /**\n * @param headers - Request headers containing permission data\n * @returns Array of toolset names from headers\n */\n #parseHeaderPermissions(headers?: Record<string, string>): string[] {\n if (!headers) {\n return [];\n }\n\n // Find header value using case-insensitive lookup\n const headerValue = this.#findHeaderCaseInsensitive(\n headers,\n this.normalizedHeaderName\n );\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 '${this.normalizedHeaderName}':`,\n error\n );\n return [];\n }\n }\n\n /**\n * @param headers - The headers object to search\n * @param normalizedKey - The lowercase key to search for\n * @returns The header value if found\n */\n #findHeaderCaseInsensitive(\n headers: Record<string, string>,\n normalizedKey: string\n ): string | undefined {\n // Fast path: check if key exists as-is (common case with Fastify's lowercased headers)\n if (headers[normalizedKey] !== undefined) {\n return headers[normalizedKey];\n }\n // Slow path: iterate and compare lowercase\n for (const [key, value] of Object.entries(headers)) {\n if (key.toLowerCase() === normalizedKey) {\n return value;\n }\n }\n return undefined;\n }\n\n /**\n * @param clientId - The unique identifier for the client\n * @returns Array of toolset names from configuration\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 * @param clientId - The unique identifier for the client\n * @returns Array of toolset names if successful, null if resolver fails\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 * @param clientId - The unique identifier for the client\n * @returns Array of toolset names if found, null if client not in map\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 clearCache(): void {\n this.cache.clear();\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 { z } from \"zod\";\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 PermissionAwareFastifyTransportOptions,\n} from \"./permissions.types.js\";\nimport type { CustomEndpointDefinition } from \"../http/http.types.js\";\nimport { registerCustomEndpoints } from \"../http/http.utils.js\";\n\nconst mcpClientIdSchema = z\n .string({ message: \"Missing required mcp-client-id header\" })\n .trim()\n .min(1, \"mcp-client-id header must not be empty\");\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 customEndpoints?: CustomEndpointDefinition[];\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 failedToolsets: string[];\n }>({\n onEvict: (_key, bundle) => {\n // Clean up all sessions when a client bundle is evicted\n this.#cleanupBundle(bundle);\n },\n });\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 customEndpoints: options.customEndpoints,\n };\n this.configSchema = configSchema;\n }\n\n static builder() {\n let _defaultManager: DynamicToolManager;\n let _createPermissionAwareBundle: (context: ClientRequestContext) => Promise<PermissionAwareBundle>;\n const opts: PermissionAwareFastifyTransportOptions = {};\n let _configSchema: object | undefined;\n const builder = {\n defaultManager(value: DynamicToolManager) { _defaultManager = value; return builder; },\n createPermissionAwareBundle(value: (context: ClientRequestContext) => Promise<PermissionAwareBundle>) { _createPermissionAwareBundle = value; return builder; },\n host(value: string) { opts.host = value; return builder; },\n port(value: number) { opts.port = value; return builder; },\n basePath(value: string) { opts.basePath = value; return builder; },\n cors(value: boolean) { opts.cors = value; return builder; },\n logger(value: boolean) { opts.logger = value; return builder; },\n app(value: FastifyInstance) { opts.app = value; return builder; },\n customEndpoints(value: CustomEndpointDefinition[]) { opts.customEndpoints = value; return builder; },\n configSchema(value: object) { _configSchema = value; return builder; },\n build() { return new PermissionAwareFastifyTransport(_defaultManager, _createPermissionAwareBundle, opts, _configSchema); },\n };\n return builder;\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.#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 // Register custom endpoints if provided with permission context\n // IMPORTANT: Only register if customEndpoints is provided AND has items\n if (this.options.customEndpoints && this.options.customEndpoints.length > 0) {\n registerCustomEndpoints(app, base, this.options.customEndpoints, {\n contextExtractor: async (req) => {\n // Extract client context from request\n const context = this.#extractClientContext(req);\n\n // Resolve permissions for this client\n try {\n const bundle = await this.createPermissionAwareBundle(context);\n return {\n allowedToolsets: bundle.allowedToolsets,\n failedToolsets: bundle.failedToolsets,\n };\n } catch (error) {\n // If permission resolution fails, return empty permissions\n console.warn(\n `Permission resolution failed for custom endpoint: ${error}`\n );\n return {\n allowedToolsets: [],\n failedToolsets: [],\n };\n }\n },\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\n // Stop the cache pruning interval and clear all entries (triggers cleanup)\n this.clientCache.stop(true);\n\n if (!this.options.app) {\n await this.app.close();\n }\n this.app = null;\n }\n\n /**\n * @param bundle - The client bundle to clean up\n */\n #cleanupBundle(bundle: {\n server: McpServer;\n orchestrator: ServerOrchestrator;\n sessions: Map<string, StreamableHTTPServerTransport>;\n allowedToolsets: string[];\n failedToolsets: string[];\n }): void {\n for (const [sessionId, transport] of bundle.sessions.entries()) {\n try {\n if (typeof (transport as any).close === \"function\") {\n (transport as any).close().catch((err: unknown) => {\n console.warn(`Error closing session ${sessionId}:`, err);\n });\n }\n } catch (err) {\n console.warn(`Error closing session ${sessionId}:`, err);\n }\n }\n bundle.sessions.clear();\n }\n\n /**\n * @param basePath - The base path to normalize\n * @returns Normalized base path without trailing slash\n */\n #normalizeBasePath(basePath: string): string {\n return basePath.endsWith(\"/\") ? basePath.slice(0, -1) : basePath;\n }\n\n /**\n * @param app - Fastify instance\n * @param base - Base path for routes\n */\n #registerHealthEndpoint(app: FastifyInstance, base: string): void {\n app.get(`${base}/healthz`, async () => ({ ok: true }));\n }\n\n /**\n * @param app - Fastify instance\n * @param base - Base path for routes\n */\n #registerToolsEndpoint(app: FastifyInstance, base: string): void {\n app.get(`${base}/tools`, async () => this.defaultManager.getStatus());\n }\n\n /**\n * @param app - Fastify instance\n * @param base - Base path for routes\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 * @param app - Fastify instance\n * @param base - Base path for routes\n */\n #registerMcpPostEndpoint(app: FastifyInstance, base: string): void {\n app.post(\n `${base}/mcp`,\n async (req: FastifyRequest, reply: FastifyReply) => {\n // Validate mcp-client-id header\n const parseResult = mcpClientIdSchema.safeParse(\n req.headers[\"mcp-client-id\"]\n );\n if (!parseResult.success) {\n reply.code(400);\n return {\n jsonrpc: \"2.0\",\n error: { code: -32600, message: parseResult.error.issues[0].message },\n id: null,\n };\n }\n\n // Extract client context from request\n const context = this.#extractClientContext(req);\n\n // Get or create permission-aware bundle for this client\n let bundle = this.clientCache.get(context.clientId);\n if (!bundle) {\n try {\n const created = await this.createPermissionAwareBundle(context);\n\n // Log any failed toolsets for debugging\n if (created.failedToolsets.length > 0) {\n console.warn(\n `Client ${context.clientId} had ${created.failedToolsets.length} toolsets fail to enable: ` +\n `[${created.failedToolsets.join(\", \")}]. ` +\n `Successfully enabled: [${created.allowedToolsets.join(\", \")}]`\n );\n }\n\n const providedSessions = (created as { sessions?: Map<string, StreamableHTTPServerTransport> }).sessions;\n bundle = {\n server: created.server,\n orchestrator: created.orchestrator,\n allowedToolsets: created.allowedToolsets,\n failedToolsets: created.failedToolsets,\n sessions:\n providedSessions instanceof Map ? providedSessions : new Map(),\n };\n 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 * @param app - Fastify instance\n * @param base - Base path for routes\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 * @param app - Fastify instance\n * @param base - Base path for routes\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 * @param req - Fastify request object\n * @returns Client request context with ID and headers\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 * @param message - Generic error message to return to client\n * @param code - JSON-RPC error code\n * @returns JSON-RPC error response object\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 { ExposurePolicy } from \"../types/index.js\";\nimport type {\n CreatePermissionBasedMcpServerOptions,\n McpServerHandle,\n} from \"./server.types.js\";\nimport {\n validatePermissionConfig,\n createPermissionAwareBundle,\n sanitizeExposurePolicyForPermissions,\n} from \"../permissions/permissions.utils.js\";\nimport { validateSessionContextConfig } from \"../session/session.utils.js\";\nimport { PermissionResolver } from \"../permissions/PermissionResolver.js\";\nimport { ServerOrchestrator } from \"../core/ServerOrchestrator.js\";\nimport { PermissionAwareFastifyTransport } from \"../permissions/PermissionAwareFastifyTransport.js\";\n\nexport async function createPermissionBasedMcpServer(\n options: CreatePermissionBasedMcpServerOptions\n): Promise<McpServerHandle> {\n // --- Validate ---\n validatePermissionOptions(options);\n\n const sanitizedPolicy = sanitizeExposurePolicyForPermissions(options.exposurePolicy);\n const permissionResolver = buildPermissionResolver(options);\n\n // --- Base server & status-only orchestrator ---\n const baseServer: McpServer = options.createServer();\n const baseOrchestrator = buildPermissionOrchestrator(baseServer, options, sanitizedPolicy);\n\n // --- Per-client bundle factory ---\n const createBundle = createPermissionAwareBundle(\n createClientOrchestratorFactory(options, sanitizedPolicy),\n permissionResolver\n );\n\n // --- Transport ---\n const transport = buildPermissionTransport(options, baseOrchestrator.getManager(), createBundle);\n\n return {\n server: baseServer,\n start: () => transport.start(),\n close: async () => {\n try {\n await transport.stop();\n } finally {\n permissionResolver.clearCache();\n }\n },\n };\n}\n\n// ---------------------------------------------------------------------------\n// Named helper functions\n// ---------------------------------------------------------------------------\n\n/**\n * Consolidates all upfront validation guards for permission-based servers.\n *\n * @param options - Server creation options to validate\n */\nfunction validatePermissionOptions(\n options: CreatePermissionBasedMcpServerOptions\n): void {\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 validatePermissionConfig(options.permissions);\n\n if (options.sessionContext) {\n validateSessionContextConfig(options.sessionContext);\n console.warn(\n \"Session context support for permission-based servers is limited. \" +\n \"The base context will be used for module loaders.\"\n );\n }\n\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 if (typeof options.createServer !== \"function\") {\n throw new Error(\n \"createPermissionBasedMcpServer: `createServer` (factory) is required\"\n );\n }\n}\n\n/**\n * Builds a PermissionResolver from the options config.\n *\n * @param options - Server creation options containing permission config\n * @returns A configured PermissionResolver\n */\nfunction buildPermissionResolver(\n options: CreatePermissionBasedMcpServerOptions\n): PermissionResolver {\n const builder = PermissionResolver.builder()\n .source(options.permissions.source)\n .headerName(options.permissions.headerName ?? \"mcp-toolset-permissions\")\n .staticMap(options.permissions.staticMap ?? {})\n .defaultPermissions(options.permissions.defaultPermissions ?? []);\n\n if (options.permissions.resolver) {\n builder.resolver(options.permissions.resolver);\n }\n\n return builder.build();\n}\n\n/**\n * Builds a ServerOrchestrator configured for permission-based operation\n * (STATIC mode, empty toolsets, no meta-tools, no notifier).\n *\n * @param server - The MCP server instance\n * @param options - Server creation options (catalog, moduleLoaders, context)\n * @param policy - Sanitized exposure policy\n * @returns Orchestrator configured for permission-based operation\n */\nfunction buildPermissionOrchestrator(\n server: McpServer,\n options: CreatePermissionBasedMcpServerOptions,\n policy: ExposurePolicy | undefined\n): ServerOrchestrator {\n const builder = ServerOrchestrator.builder()\n .server(server)\n .catalog(options.catalog)\n .moduleLoaders(options.moduleLoaders ?? {})\n .context(options.context)\n .startup({ mode: \"STATIC\", toolsets: [] })\n .registerMetaTools(false);\n\n if (policy) {\n builder.exposurePolicy(policy);\n }\n\n return builder.build();\n}\n\n/**\n * Creates the callback that produces a fresh server + orchestrator per client,\n * scoped to the client's allowed toolsets.\n *\n * @param options - Server creation options\n * @param policy - Sanitized exposure policy\n * @returns Factory callback that accepts allowed toolsets and returns a server/orchestrator pair\n */\nfunction createClientOrchestratorFactory(\n options: CreatePermissionBasedMcpServerOptions,\n policy: ExposurePolicy | undefined\n): (allowedToolsets: string[]) => { server: McpServer; orchestrator: ServerOrchestrator } {\n return (allowedToolsets: string[]) => {\n const clientServer: McpServer = options.createServer();\n const clientOrchestrator = buildPermissionOrchestrator(clientServer, options, policy);\n return { server: clientServer, orchestrator: clientOrchestrator };\n };\n}\n\n/**\n * Builds the PermissionAwareFastifyTransport, handling conditional `.app()`\n * and `.customEndpoints()` chaining.\n *\n * @param options - Server creation options (http config)\n * @param manager - Default DynamicToolManager for status endpoints\n * @param createBundle - Permission-aware bundle creator\n * @returns A configured PermissionAwareFastifyTransport\n */\nfunction buildPermissionTransport(\n options: CreatePermissionBasedMcpServerOptions,\n manager: ReturnType<ServerOrchestrator[\"getManager\"]>,\n createBundle: ReturnType<typeof createPermissionAwareBundle>\n): PermissionAwareFastifyTransport {\n const builder = PermissionAwareFastifyTransport.builder()\n .defaultManager(manager)\n .createPermissionAwareBundle(createBundle)\n .host(options.http?.host ?? \"0.0.0.0\")\n .port(options.http?.port ?? 3000)\n .basePath(options.http?.basePath ?? \"/\")\n .cors(options.http?.cors ?? true)\n .logger(options.http?.logger ?? false);\n\n if (options.http?.app) {\n builder.app(options.http.app);\n }\n if (options.http?.customEndpoints) {\n builder.customEndpoints(options.http.customEndpoints);\n }\n if (options.configSchema) {\n builder.configSchema(options.configSchema);\n }\n\n return builder.build();\n}\n"],"names":["DEFAULT_KEYS","RESERVED_TOOLSET_KEYS","ToolsetValidator","options","__publicField","opts","builder","value","env","args","input","catalog","raw","s","valid","result","name","toolsets","modules","def","m","sanitized","available","toolsetNames","error","source","key","ModuleResolver","context","collected","toolsetName","modKey","loader","loaded","err","ToolingError","message","code","details","_options","ToolRegistry","toolsetKey","toolName","set","tools","t","safe","k","v","DynamicToolManager","skipNotification","validation","policyCheck","registeredTools","toolCount","resolvedTools","mapped","tool","activeToolsets","results","res","successAll","r","anySuccess","all","META_TOOLSET_KEY","registerMetaTools","server","manager","toolRegistry","z","byToolset","items","payload","status","ServerOrchestrator","startup","resolved","managerBuilder","initial","mode","names","isValid","_ClientResourceCache","__privateAdd","_ClientResourceCache_instances","pruneEvery","entry","resource","newEntry","__privateMethod","callEvictCallback_fn","clearEntries","entries","lruKey","now","keysToDelete","ClientResourceCache","defineEndpoint","definition","definePermissionAwareEndpoint","registerCustomEndpoints","app","basePath","endpoints","reservedPaths","endpoint","fullPath","reserved","method","req","reply","clientIdHeader","clientId","randomUUID","body","bodyResult","createValidationError","query","queryResult","params","paramsResult","customRequest","additionalContext","responseResult","field","mcpClientIdSchema","FastifyTransport","defaultManager","createBundle","configSchema","sessionContextResolver","baseContext","_key","bundle","_defaultManager","_createBundle","_configSchema","_sessionContextResolver","_baseContext","Fastify","cors","base","_req","parseResult","cacheKey","mergedContext","created","sessionId","transport","isInitializeRequest","newSessionId","StreamableHTTPServerTransport","sid","sessionRequestContext","headers","rawQuery","SessionContextResolver","config","request","parsedConfig","resolver","rawValue","jsonString","parsed","filtered","sessionConfig","override","baseValue","sortedKeys","normalizedObj","createHash","validateSessionContextConfig","validateConfigExists","validateEnabledField","validateQueryParamConfig","validateContextResolver","validateMergeStrategy","i","startupConfigSchema","validateStartupConfig","formatted","createToolsChangedNotifier","hasNotifierA","hasNotifierB","target","resolveMetaToolsFlag","explicit","createMcpServer","validateOptions","shouldRegisterMetaTools","buildSessionContextResolver","notifyToolsChanged","baseServer","baseOrchestrator","buildOrchestrator","bundleFactory","createBundleFactory","buildTransport","effectiveContext","clientServer","clientOrchestrator","validatePermissionConfig","validateSourceField","validateConfigBasedPermissions","validateTypes","validateStaticMapValues","staticMap","permissions","createPermissionAwareBundle","originalCreateBundle","permissionResolver","requestedToolsets","enabledToolsets","failedToolsets","sanitizeExposurePolicyForPermissions","policy","_PermissionResolver","_PermissionResolver_instances","parseHeaderPermissions_fn","resolveConfigPermissions_fn","headerValue","findHeaderCaseInsensitive_fn","normalizedKey","resolverResult","tryResolverFunction_fn","staticResult","lookupStaticMap_fn","PermissionResolver","_PermissionAwareFastifyTransport","_PermissionAwareFastifyTransport_instances","cleanupBundle_fn","_createPermissionAwareBundle","normalizeBasePath_fn","registerHealthEndpoint_fn","registerToolsEndpoint_fn","registerConfigDiscoveryEndpoint_fn","registerMcpPostEndpoint_fn","registerMcpGetEndpoint_fn","registerMcpDeleteEndpoint_fn","extractClientContext_fn","providedSessions","createSafeErrorResponse_fn","PermissionAwareFastifyTransport","createPermissionBasedMcpServer","validatePermissionOptions","sanitizedPolicy","buildPermissionResolver","buildPermissionOrchestrator","createClientOrchestratorFactory","buildPermissionTransport","allowedToolsets"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../src/mode/mode.types.ts","../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/http.utils.ts","../src/http/FastifyTransport.ts","../src/session/SessionContextResolver.ts","../src/session/session.utils.ts","../src/server/server.utils.ts","../src/server/createMcpServer.ts","../src/permissions/permissions.utils.ts","../src/permissions/PermissionResolver.ts","../src/permissions/PermissionAwareFastifyTransport.ts","../src/server/createPermissionBasedMcpServer.ts"],"sourcesContent":["import type { ToolSetCatalog, ModuleLoader } from \"../types/index.js\";\n\nexport interface ModeResolverKeys {\n dynamic?: string[];\n toolsets?: string[];\n}\n\nexport interface ModeResolverOptions {\n keys?: ModeResolverKeys;\n}\n\nexport const 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 const RESERVED_TOOLSET_KEYS = [\"_meta\"];\n\nexport interface ModuleResolverOptions {\n catalog: ToolSetCatalog;\n moduleLoaders?: Record<string, ModuleLoader>;\n}\n","import type { Mode, ToolSetCatalog } from \"../types/index.js\";\nimport type { ModeResolverKeys, ModeResolverOptions } from \"./mode.types.js\";\nimport { DEFAULT_KEYS } from \"./mode.types.js\";\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 static builder() {\n const opts: ModeResolverOptions = {};\n const builder = {\n keys(value: ModeResolverKeys) { opts.keys = value; return builder; },\n build() { return new ToolsetValidator(opts); },\n };\n return builder;\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 this.createInvalidNameError(name, catalog);\n }\n const sanitized = name.trim();\n if (sanitized.length === 0) {\n return this.createInvalidNameError(sanitized, catalog);\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 /**\n * @param name - The invalid name value\n * @param catalog - The toolset catalog for listing available options\n * @returns Validation result with descriptive error message\n */\n private createInvalidNameError(\n name: unknown,\n catalog: ToolSetCatalog\n ): { isValid: false; error: string } {\n const available = Object.keys(catalog).join(\", \");\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: ${available}`,\n };\n }\n return {\n isValid: false,\n error: `Empty toolset name provided. Available toolsets: ${available}`,\n };\n }\n\n /**\n * @param toolsetNames - Array of toolset names to validate\n * @param catalog - The toolset catalog to validate against\n * @returns Validation result with modules array if valid\n */\n public validateToolsetModules(\n toolsetNames: string[],\n catalog: ToolSetCatalog\n ): { isValid: boolean; modules?: string[]; error?: string } {\n try {\n // Verify all toolset names exist in catalog first\n for (const name of toolsetNames) {\n if (!catalog[name]) {\n return {\n isValid: false,\n error: `Toolset '${name}' not found in catalog`,\n };\n }\n }\n\n // Get modules - empty array is valid (toolset may have only direct tools)\n const modules = this.getModulesForToolSets(toolsetNames, catalog);\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\";\nimport type { ModuleResolverOptions } from \"./mode.types.js\";\nimport { RESERVED_TOOLSET_KEYS } from \"./mode.types.js\";\n\nexport class ModuleResolver {\n private readonly catalog: ToolSetCatalog;\n private readonly moduleLoaders: Record<string, ModuleLoader>;\n\n constructor(options: ModuleResolverOptions) {\n // Validate catalog doesn't use reserved keys\n for (const key of RESERVED_TOOLSET_KEYS) {\n if (key in options.catalog) {\n throw new Error(\n `Toolset key '${key}' is reserved for internal use and cannot be used in the catalog`\n );\n }\n }\n this.catalog = options.catalog;\n this.moduleLoaders = options.moduleLoaders ?? {};\n }\n\n static builder() {\n const opts: Partial<ModuleResolverOptions> = {};\n const builder = {\n catalog(value: ToolSetCatalog) { opts.catalog = value; return builder; },\n moduleLoaders(value: Record<string, ModuleLoader>) { opts.moduleLoaders = value; return builder; },\n build() { return new ModuleResolver(opts as ModuleResolverOptions); },\n };\n return builder;\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 // Check for reserved keys (defense in depth)\n if (RESERVED_TOOLSET_KEYS.includes(sanitized)) {\n return {\n isValid: false,\n error: `Toolset key '${sanitized}' is reserved for internal use`,\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 this.collectDirectTools(def, collected);\n await this.loadModuleTools(def, name, context, collected);\n }\n return collected;\n }\n\n /**\n * @param def - The toolset definition\n * @param collected - Mutable array to append direct tools to\n */\n private collectDirectTools(\n def: ToolSetDefinition,\n collected: McpToolDefinition[]\n ): void {\n if (Array.isArray(def.tools) && def.tools.length > 0) {\n collected.push(...def.tools);\n }\n }\n\n /**\n * @param def - The toolset definition containing module keys\n * @param toolsetName - The toolset name for error messages\n * @param context - Optional context passed to module loaders\n * @param collected - Mutable array to append loaded tools to\n */\n private async loadModuleTools(\n def: ToolSetDefinition,\n toolsetName: string,\n context: unknown,\n collected: McpToolDefinition[]\n ): Promise<void> {\n if (!Array.isArray(def.modules) || def.modules.length === 0) return;\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 '${toolsetName}':`,\n err\n );\n }\n }\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\";\nimport type { ToolRegistryOptions } from \"./core.types.js\";\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 static builder() {\n const opts: ToolRegistryOptions = {};\n const builder = {\n namespaceWithToolset(value: boolean) { opts.namespaceWithToolset = value; return builder; },\n build() { return new ToolRegistry(opts); },\n };\n return builder;\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\";\nimport type { DynamicToolManagerOptions } from \"./core.types.js\";\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 ?? ToolRegistry.builder().namespaceWithToolset(true).build();\n }\n\n static builder() {\n const opts: Partial<DynamicToolManagerOptions> = {};\n const builder = {\n server(value: McpServer) { opts.server = value; return builder; },\n resolver(value: ModuleResolver) { opts.resolver = value; return builder; },\n context(value: unknown) { opts.context = value; return builder; },\n onToolsListChanged(value: () => Promise<void> | void) { opts.onToolsListChanged = value; return builder; },\n exposurePolicy(value: ExposurePolicy) { opts.exposurePolicy = value; return builder; },\n toolRegistry(value: ToolRegistry) { opts.toolRegistry = value; return builder; },\n build() { return new DynamicToolManager(opts as DynamicToolManagerOptions); },\n };\n return builder;\n }\n\n /**\n * @returns Promise that resolves when notification is sent (or skipped)\n */\n private async notifyToolsChanged(): Promise<void> {\n if (!this.onToolsListChanged) return;\n try {\n await this.onToolsListChanged();\n } catch (err) {\n console.warn(\"Failed to send tool list change notification:\", err);\n }\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 /**\n * Enables a single toolset by name.\n * @param toolsetName - The name of the toolset to enable\n * @param skipNotification - If true, skips the tool list change notification\n * @returns Result object with success status and message\n */\n public async enableToolset(\n toolsetName: string,\n skipNotification = false\n ): Promise<{ success: boolean; message: string }> {\n const validation = this.validateToolsetForEnable(toolsetName);\n if (\"message\" in validation) return validation;\n\n const { sanitized } = validation;\n\n // Check exposure policies BEFORE resolving tools to fail fast\n const policyCheck = this.checkExposurePolicy(sanitized);\n if (!policyCheck.allowed) {\n return { success: false, message: policyCheck.message };\n }\n\n // Track tools registered for this enable operation to allow rollback\n const registeredTools: string[] = [];\n\n try {\n const toolCount = await this.resolveAndRegisterTools(sanitized, registeredTools);\n\n // Track state only after successful registration\n this.activeToolsets.add(sanitized);\n\n // Notify list change (unless skipped for batch operations)\n if (!skipNotification) {\n await this.notifyToolsChanged();\n }\n\n return this.buildEnableResult(sanitized, toolCount);\n } catch (error) {\n this.handlePartialFailure(sanitized, registeredTools);\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 /**\n * @param toolsetName - The raw toolset name to validate\n * @returns Error result if invalid, or `{ sanitized }` to continue\n */\n private validateToolsetForEnable(\n toolsetName: string\n ): { success: boolean; message: string } | { sanitized: 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 if (this.activeToolsets.has(validation.sanitized)) {\n return {\n success: false,\n message: `Toolset '${validation.sanitized}' is already enabled.`,\n };\n }\n return { sanitized: validation.sanitized };\n }\n\n /**\n * @param sanitized - The validated toolset name\n * @param registeredTools - Mutable array tracking registered tool names for rollback\n * @returns The number of tools resolved\n */\n private async resolveAndRegisterTools(\n sanitized: string,\n registeredTools: string[]\n ): Promise<number> {\n const resolvedTools = await this.resolver.resolveToolsForToolsets(\n [sanitized],\n this.context\n );\n\n if (resolvedTools && resolvedTools.length > 0) {\n const mapped = this.toolRegistry.mapAndValidate(sanitized, resolvedTools);\n for (const tool of mapped) {\n this.registerSingleTool(tool, sanitized);\n registeredTools.push(tool.name);\n }\n }\n\n return resolvedTools?.length ?? 0;\n }\n\n /**\n * @param sanitized - The toolset name\n * @param toolCount - Number of tools registered\n * @returns Success result object\n */\n private buildEnableResult(\n sanitized: string,\n toolCount: number\n ): { success: boolean; message: string } {\n return {\n success: true,\n message: `Toolset '${sanitized}' enabled successfully. Registered ${toolCount} tools.`,\n };\n }\n\n /**\n * @param sanitized - The toolset name that partially failed\n * @param registeredTools - Tools that were registered before the failure\n */\n private handlePartialFailure(\n sanitized: string,\n registeredTools: string[]\n ): void {\n if (registeredTools.length > 0) {\n console.warn(\n `Partial failure enabling toolset '${sanitized}'. ` +\n `${registeredTools.length} tools were registered but toolset activation failed. ` +\n `Tools remain registered due to MCP limitations: ${registeredTools.join(\", \")}`\n );\n }\n }\n\n /**\n * @param toolsetName - The sanitized toolset name to check\n * @returns Object indicating if allowed and reason message if not\n */\n private checkExposurePolicy(toolsetName: string): {\n allowed: boolean;\n message: string;\n } {\n if (\n this.exposurePolicy?.allowlist &&\n !this.exposurePolicy.allowlist.includes(toolsetName)\n ) {\n return {\n allowed: false,\n message: `Toolset '${toolsetName}' is not allowed by policy.`,\n };\n }\n if (\n this.exposurePolicy?.denylist &&\n this.exposurePolicy.denylist.includes(toolsetName)\n ) {\n return {\n allowed: false,\n message: `Toolset '${toolsetName}' 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 [toolsetName],\n Array.from(this.activeToolsets)\n );\n return {\n allowed: false,\n message: `Activation exceeds maxActiveToolsets (${this.exposurePolicy.maxActiveToolsets}).`,\n };\n }\n }\n return { allowed: true, message: \"\" };\n }\n\n /**\n * @param tool - The tool definition to register\n * @param toolsetKey - The toolset key for tracking\n */\n private registerSingleTool(tool: McpToolDefinition, toolsetKey: string): void {\n // Only pass annotations if they exist and are not empty\n const hasAnnotations =\n tool.annotations && Object.keys(tool.annotations).length > 0;\n\n if (hasAnnotations && tool.annotations) {\n this.server.tool(\n tool.name,\n tool.description,\n tool.inputSchema as Parameters<typeof this.server.tool>[2],\n tool.annotations,\n async (args: Record<string, unknown>) => {\n return await tool.handler(args);\n }\n );\n } else {\n // Legacy 4-parameter call when no annotations\n this.server.tool(\n tool.name,\n tool.description,\n tool.inputSchema as Parameters<typeof this.server.tool>[2],\n async (args: Record<string, unknown>) => {\n return await tool.handler(args);\n }\n );\n }\n this.toolRegistry.addForToolset(toolsetKey, tool.name);\n }\n\n /**\n * @param toolsetName - The name of the toolset to disable\n * @returns Result object with success status and message\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 await this.notifyToolsChanged();\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 /**\n * @param toolsetNames - Array of toolset names to enable\n * @returns Result object with overall success status and individual results\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\n // Enable each toolset, skipping individual notifications\n for (const name of toolsetNames) {\n try {\n const res = await this.enableToolset(name, true);\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\n const successAll = results.every((r) => r.success);\n const anySuccess = results.some((r) => r.success);\n const message = successAll\n ? \"All toolsets enabled\"\n : anySuccess\n ? \"Some toolsets failed to enable\"\n : \"All toolsets failed to enable\";\n\n // Send a single notification after batch is complete (if any changes occurred)\n if (anySuccess) {\n await this.notifyToolsChanged();\n }\n\n return { success: successAll, results, message };\n }\n\n /**\n * @returns Result object with overall success status and individual results\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\";\nimport { ToolRegistry } from \"../core/ToolRegistry.js\";\n\n/**\n * Reserved toolset key for meta-tools.\n * Meta-tools are registered under this key to enable collision detection\n * and tracking via the ToolRegistry.\n */\nexport const META_TOOLSET_KEY = \"_meta\";\n\n/**\n * Registers meta-tools on the MCP server for toolset management.\n *\n * In DYNAMIC mode, all meta-tools are registered:\n * - enable_toolset, disable_toolset: For runtime toolset management\n * - list_toolsets, describe_toolset: For toolset discovery\n * - list_tools: For listing registered tools\n *\n * In STATIC mode, only list_tools is registered since toolsets are fixed at startup.\n *\n * Meta-tools are registered with the ToolRegistry under the reserved \"_meta\" toolset key\n * to enable collision detection with user-defined tools.\n *\n * @param server - The MCP server to register tools on\n * @param manager - The DynamicToolManager instance\n * @param toolRegistry - The ToolRegistry for collision detection\n * @param options - Configuration options including the mode\n */\nexport function registerMetaTools(\n server: McpServer,\n manager: DynamicToolManager,\n toolRegistry: ToolRegistry,\n options?: { mode?: Exclude<Mode, \"ALL\"> }\n): void {\n const mode = options?.mode ?? \"DYNAMIC\";\n\n // Dynamic-mode only tools: enable/disable toolsets at runtime\n if (mode === \"DYNAMIC\") {\n // Register with ToolRegistry for collision detection before server.tool()\n toolRegistry.addForToolset(META_TOOLSET_KEY, \"enable_toolset\");\n server.tool(\n \"enable_toolset\",\n \"Enable a toolset by name\",\n { name: z.string().describe(\"Toolset name\") },\n { destructiveHint: true, idempotentHint: true },\n async (args: { name: string }) => {\n const result = await manager.enableToolset(args.name);\n return {\n content: [{ type: \"text\", text: JSON.stringify(result) }],\n };\n }\n );\n\n toolRegistry.addForToolset(META_TOOLSET_KEY, \"disable_toolset\");\n server.tool(\n \"disable_toolset\",\n \"Disable a toolset by name (state only)\",\n { name: z.string().describe(\"Toolset name\") },\n { destructiveHint: true, idempotentHint: true },\n async (args: { name: string }) => {\n const result = await manager.disableToolset(args.name);\n return {\n content: [{ type: \"text\", text: JSON.stringify(result) }],\n };\n }\n );\n\n toolRegistry.addForToolset(META_TOOLSET_KEY, \"list_toolsets\");\n server.tool(\n \"list_toolsets\",\n \"List available toolsets with active status and definitions\",\n {},\n { readOnlyHint: true, idempotentHint: true },\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 toolRegistry.addForToolset(META_TOOLSET_KEY, \"describe_toolset\");\n server.tool(\n \"describe_toolset\",\n \"Describe a toolset with definition, active status and tools\",\n { name: z.string().describe(\"Toolset name\") },\n { readOnlyHint: true, idempotentHint: true },\n async (args: { name: string }) => {\n const def = manager.getToolsetDefinition(args.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 '${args.name}'` }),\n },\n ],\n };\n }\n const payload = {\n key: args.name,\n active: manager.isActive(args.name),\n definition: {\n name: def.name,\n description: def.description,\n modules: def.modules ?? [],\n decisionCriteria: def.decisionCriteria ?? undefined,\n },\n tools: byToolset[args.name] ?? [],\n };\n return {\n content: [{ type: \"text\", text: JSON.stringify(payload) }],\n };\n }\n );\n }\n\n // list_tools is available in both modes\n toolRegistry.addForToolset(META_TOOLSET_KEY, \"list_tools\");\n server.tool(\n \"list_tools\",\n \"List currently registered tool names (best effort)\",\n {},\n { readOnlyHint: true, idempotentHint: true },\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 {\n ExposurePolicy,\n Mode,\n ModuleLoader,\n ToolSetCatalog,\n} from \"../types/index.js\";\nimport { ToolRegistry } from \"./ToolRegistry.js\";\nimport type { ServerOrchestratorOptions } from \"./core.types.js\";\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 private readonly initPromise: Promise<void>;\n private initError: Error | null = null;\n\n constructor(options: ServerOrchestratorOptions) {\n this.toolsetValidator = ToolsetValidator.builder().build();\n const startup = options.startup ?? {};\n const resolved = this.resolveStartupConfig(startup, options.catalog);\n this.mode = resolved.mode;\n this.resolver = ModuleResolver.builder()\n .catalog(options.catalog)\n .moduleLoaders(options.moduleLoaders ?? {})\n .build();\n const toolRegistry = ToolRegistry.builder()\n .namespaceWithToolset(\n options.exposurePolicy?.namespaceToolsWithSetKey ?? true\n )\n .build();\n const managerBuilder = DynamicToolManager.builder()\n .server(options.server)\n .resolver(this.resolver)\n .context(options.context)\n .toolRegistry(toolRegistry);\n\n if (options.notifyToolsListChanged) {\n managerBuilder.onToolsListChanged(options.notifyToolsListChanged);\n }\n if (options.exposurePolicy) {\n managerBuilder.exposurePolicy(options.exposurePolicy);\n }\n\n this.manager = managerBuilder.build();\n\n // Register meta-tools only if requested (default true)\n if (options.registerMetaTools !== false) {\n registerMetaTools(options.server, this.manager, toolRegistry, { mode: this.mode });\n }\n\n // Startup behavior - store promise for async initialization\n const initial = resolved.toolsets;\n this.initPromise = this.initializeToolsets(initial);\n }\n\n static builder() {\n const opts: Partial<ServerOrchestratorOptions> = {};\n const builder = {\n server(value: McpServer) { opts.server = value; return builder; },\n catalog(value: ToolSetCatalog) { opts.catalog = value; return builder; },\n moduleLoaders(value: Record<string, ModuleLoader>) { opts.moduleLoaders = value; return builder; },\n exposurePolicy(value: ExposurePolicy) { opts.exposurePolicy = value; return builder; },\n context(value: unknown) { opts.context = value; return builder; },\n notifyToolsListChanged(value: () => Promise<void> | void) { opts.notifyToolsListChanged = value; return builder; },\n startup(value: { mode?: Exclude<Mode, \"ALL\">; toolsets?: string[] | \"ALL\" }) { opts.startup = value; return builder; },\n registerMetaTools(value: boolean) { opts.registerMetaTools = value; return builder; },\n build() { return new ServerOrchestrator(opts as ServerOrchestratorOptions); },\n };\n return builder;\n }\n\n /**\n * @param initial - The toolsets to initialize or \"ALL\"\n * @returns Promise that resolves when initialization is complete\n */\n private async initializeToolsets(\n initial: string[] | \"ALL\" | undefined\n ): Promise<void> {\n try {\n if (initial === \"ALL\") {\n await this.manager.enableToolsets(this.resolver.getAvailableToolsets());\n } else if (Array.isArray(initial) && initial.length > 0) {\n await this.manager.enableToolsets(initial);\n }\n } catch (error) {\n this.initError =\n error instanceof Error ? error : new Error(String(error));\n console.error(\"Failed to initialize toolsets:\", this.initError);\n }\n }\n\n public async ensureReady(): Promise<void> {\n await this.initPromise;\n if (this.initError) {\n throw this.initError;\n }\n }\n\n public async isReady(): Promise<boolean> {\n await this.initPromise;\n return this.initError === null;\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 if (startup.mode) {\n return this.resolveExplicitMode(startup.mode, startup.toolsets, catalog);\n }\n return this.inferModeFromToolsets(startup, catalog);\n }\n\n /**\n * @param mode - The explicit mode\n * @param toolsets - Optional toolsets from startup config\n * @param catalog - The toolset catalog to validate against\n * @returns Resolved mode and toolsets\n */\n private resolveExplicitMode(\n mode: Exclude<Mode, \"ALL\">,\n toolsets: string[] | \"ALL\" | undefined,\n catalog: ToolSetCatalog\n ): { mode: Exclude<Mode, \"ALL\">; toolsets?: string[] | \"ALL\" } {\n if (mode === \"DYNAMIC\" && toolsets) {\n console.warn(\"startup.toolsets provided but ignored in DYNAMIC mode\");\n return { mode: \"DYNAMIC\" };\n }\n if (mode === \"STATIC\") {\n if (toolsets === \"ALL\")\n return { mode: \"STATIC\", toolsets: \"ALL\" };\n const names = Array.isArray(toolsets) ? toolsets : [];\n const valid = this.validateAndCollectToolsets(names, catalog);\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 };\n }\n\n /**\n * @param startup - Startup config without an explicit mode\n * @param catalog - The toolset catalog to validate against\n * @returns Inferred mode and toolsets\n */\n private inferModeFromToolsets(\n startup: { toolsets?: string[] | \"ALL\" },\n catalog: ToolSetCatalog\n ): { mode: Exclude<Mode, \"ALL\">; toolsets?: string[] | \"ALL\" } {\n if (startup.toolsets === \"ALL\") return { mode: \"STATIC\", toolsets: \"ALL\" };\n if (Array.isArray(startup.toolsets) && startup.toolsets.length > 0) {\n const valid = this.validateAndCollectToolsets(startup.toolsets, catalog);\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 return { mode: \"DYNAMIC\" };\n }\n\n /**\n * @param names - Array of toolset names to validate\n * @param catalog - The toolset catalog to validate against\n * @returns Array of valid, sanitized toolset names\n */\n private validateAndCollectToolsets(\n names: string[],\n catalog: ToolSetCatalog\n ): string[] {\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 return valid;\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","import type { ClientResourceCacheOptions, Entry } from \"./session.types.js\";\n\nexport class ClientResourceCache<T> {\n private storage = new Map<string, Entry<T>>();\n private maxSize: number;\n private ttlMs: number;\n private onEvict?: (key: string, resource: T) => void | Promise<void>;\n // Use ReturnType<typeof setInterval> for cross-env typings without NodeJS namespace\n private pruneInterval?: ReturnType<typeof setInterval>;\n\n constructor(options: ClientResourceCacheOptions<T> = {}) {\n this.maxSize = options.maxSize ?? 1000;\n this.ttlMs = options.ttlMs ?? 1000 * 60 * 60;\n this.onEvict = options.onEvict;\n const pruneEvery = options.pruneIntervalMs ?? 1000 * 60 * 10;\n this.pruneInterval = setInterval(() => this.pruneExpired(), pruneEvery);\n }\n\n static builder<T>() {\n const opts: ClientResourceCacheOptions<T> = {};\n const builder = {\n maxSize(value: number) { opts.maxSize = value; return builder; },\n ttlMs(value: number) { opts.ttlMs = value; return builder; },\n pruneIntervalMs(value: number) { opts.pruneIntervalMs = value; return builder; },\n onEvict(value: (key: string, resource: T) => void | Promise<void>) { opts.onEvict = value; return builder; },\n build() { return new ClientResourceCache<T>(opts); },\n };\n return builder;\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 /**\n * @param key - The key to remove\n */\n public delete(key: string): void {\n const entry = this.storage.get(key);\n if (entry) {\n this.storage.delete(key);\n this.#callEvictCallback(key, entry.resource);\n }\n }\n\n /**\n * @param clearEntries - If true, also removes all entries and calls onEvict for each\n */\n public stop(clearEntries = false): void {\n if (this.pruneInterval) {\n clearInterval(this.pruneInterval);\n this.pruneInterval = undefined;\n }\n if (clearEntries) {\n this.clear();\n }\n }\n\n public clear(): void {\n // Collect all entries first to avoid modification during iteration\n const entries = Array.from(this.storage.entries());\n this.storage.clear();\n for (const [key, entry] of entries) {\n this.#callEvictCallback(key, entry.resource);\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 const keysToDelete: string[] = [];\n for (const [key, entry] of this.storage.entries()) {\n if (now - entry.lastAccessed > this.ttlMs) {\n keysToDelete.push(key);\n }\n }\n // Delete after iteration to avoid modification during iteration\n for (const key of keysToDelete) {\n this.delete(key);\n }\n }\n\n /**\n * @param key - The key being evicted\n * @param resource - The resource being evicted\n */\n #callEvictCallback(key: string, resource: T): void {\n if (!this.onEvict) return;\n try {\n const result = this.onEvict(key, resource);\n // Handle async callbacks but don't await\n if (result instanceof Promise) {\n result.catch((err) => {\n console.warn(`Error in cache eviction callback for key '${key}':`, err);\n });\n }\n } catch (err) {\n console.warn(`Error in cache eviction callback for key '${key}':`, err);\n }\n }\n}\n","import type { FastifyInstance, FastifyRequest, FastifyReply } from \"fastify\";\nimport { z } from \"zod\";\nimport { randomUUID } from \"node:crypto\";\nimport type {\n CustomEndpointDefinition,\n CustomEndpointRequest,\n EndpointErrorResponse,\n HttpMethod,\n PermissionAwareEndpointHandler,\n PermissionAwareEndpointRequest,\n RegisterCustomEndpointsOptions,\n} from \"./http.types.js\";\n\n// --- defineEndpoint (from customEndpoints.ts) ---\n\n/**\n * Helper function to create type-safe custom endpoints with automatic type inference.\n * Provides better IntelliSense and type checking for endpoint definitions.\n *\n * @template TBody - Zod schema for request body\n * @template TQuery - Zod schema for query parameters\n * @template TParams - Zod schema for path parameters\n * @template TResponse - Zod schema for response\n *\n * @param definition - Endpoint definition with schemas and handler\n * @returns The same endpoint definition with full type inference\n *\n * @example\n * ```typescript\n * import { z } from \"zod\";\n * import { defineEndpoint } from \"toolception\";\n *\n * const getUsersEndpoint = defineEndpoint({\n * method: \"GET\",\n * path: \"/users\",\n * querySchema: z.object({\n * limit: z.coerce.number().int().positive().default(10),\n * role: z.enum([\"admin\", \"user\"]).optional(),\n * }),\n * responseSchema: z.object({\n * users: z.array(z.object({\n * id: z.string(),\n * name: z.string(),\n * })),\n * total: z.number(),\n * }),\n * handler: async (req) => {\n * // req.query is fully typed: { limit: number, role?: \"admin\" | \"user\" }\n * const { limit, role } = req.query;\n *\n * return {\n * users: [{ id: \"1\", name: \"Alice\" }],\n * total: 1,\n * };\n * },\n * });\n * ```\n */\nexport function defineEndpoint<\n TBody extends z.ZodTypeAny = z.ZodNever,\n TQuery extends z.ZodTypeAny = z.ZodNever,\n TParams extends z.ZodTypeAny = z.ZodNever,\n TResponse extends z.ZodTypeAny = z.ZodAny\n>(\n definition: CustomEndpointDefinition<TBody, TQuery, TParams, TResponse>\n): CustomEndpointDefinition<TBody, TQuery, TParams, TResponse> {\n return definition;\n}\n\n// --- definePermissionAwareEndpoint (from customEndpoints.ts) ---\n\n/**\n * Helper function to create permission-aware custom endpoints for permission-based servers.\n * Similar to defineEndpoint but with access to permission context in the handler.\n *\n * @template TBody - Zod schema for request body\n * @template TQuery - Zod schema for query parameters\n * @template TParams - Zod schema for path parameters\n * @template TResponse - Zod schema for response\n *\n * @param definition - Endpoint definition with permission-aware handler\n * @returns Endpoint definition compatible with permission-based servers\n *\n * @example\n * ```typescript\n * import { definePermissionAwareEndpoint } from \"toolception\";\n *\n * const statsEndpoint = definePermissionAwareEndpoint({\n * method: \"GET\",\n * path: \"/my-permissions\",\n * responseSchema: z.object({\n * toolsets: z.array(z.string()),\n * count: z.number(),\n * }),\n * handler: async (req) => {\n * // req.allowedToolsets and req.failedToolsets are available\n * return {\n * toolsets: req.allowedToolsets,\n * count: req.allowedToolsets.length,\n * };\n * },\n * });\n * ```\n */\nexport function definePermissionAwareEndpoint<\n TBody extends z.ZodTypeAny = z.ZodNever,\n TQuery extends z.ZodTypeAny = z.ZodNever,\n TParams extends z.ZodTypeAny = z.ZodNever,\n TResponse extends z.ZodTypeAny = z.ZodAny\n>(definition: {\n method: HttpMethod;\n path: string;\n bodySchema?: TBody;\n querySchema?: TQuery;\n paramsSchema?: TParams;\n responseSchema?: TResponse;\n handler: PermissionAwareEndpointHandler<TBody, TQuery, TParams, TResponse>;\n description?: string;\n}): CustomEndpointDefinition<TBody, TQuery, TParams, TResponse> {\n // Internal conversion: permission-aware handler is compatible with standard handler\n // The permission fields will be injected by the registration logic\n return definition as any;\n}\n\n// --- registerCustomEndpoints (from endpointRegistration.ts) ---\n\n/**\n * Registers custom endpoints on a Fastify instance.\n * Handles Zod validation, error responses, and type-safe request mapping.\n *\n * @param app - Fastify instance to register endpoints on\n * @param basePath - Base path for all endpoints (e.g., \"/\" or \"/api\")\n * @param endpoints - Array of custom endpoint definitions\n * @param options - Optional configuration for endpoint registration\n *\n * @example\n * ```typescript\n * registerCustomEndpoints(app, \"/api\", [\n * defineEndpoint({\n * method: \"GET\",\n * path: \"/users\",\n * querySchema: z.object({ limit: z.coerce.number() }),\n * handler: async (req) => ({ users: [] }),\n * }),\n * ]);\n * ```\n */\nexport function registerCustomEndpoints(\n app: FastifyInstance,\n basePath: string,\n endpoints: CustomEndpointDefinition[],\n options?: RegisterCustomEndpointsOptions\n): void {\n // Built-in MCP paths that should not be overridden\n const reservedPaths = [\"/mcp\", \"/healthz\", \"/tools\", \"/.well-known/mcp-config\"];\n\n for (const endpoint of endpoints) {\n const fullPath = `${basePath}${endpoint.path}`;\n\n // Check for path conflicts with built-in endpoints\n const isReserved = reservedPaths.some((reserved) =>\n fullPath.startsWith(`${basePath}${reserved}`)\n );\n\n if (isReserved) {\n console.warn(\n `Custom endpoint ${endpoint.method} ${endpoint.path} conflicts with built-in MCP endpoint. Skipping registration.`\n );\n continue;\n }\n\n // Convert method to lowercase for Fastify\n const method = endpoint.method.toLowerCase() as\n | \"get\"\n | \"post\"\n | \"put\"\n | \"delete\"\n | \"patch\";\n\n // Register the endpoint with Fastify\n app[method](fullPath, async (req: FastifyRequest, reply: FastifyReply) => {\n try {\n // Extract client ID from header or generate anonymous ID\n const clientIdHeader = (req.headers[\"mcp-client-id\"] as string)?.trim();\n const clientId =\n clientIdHeader && clientIdHeader.length > 0\n ? clientIdHeader\n : `anon-${randomUUID()}`;\n\n // Validate request body if schema provided\n let body: any = undefined;\n if (endpoint.bodySchema) {\n const bodyResult = endpoint.bodySchema.safeParse(req.body);\n if (!bodyResult.success) {\n return createValidationError(reply, \"body\", bodyResult.error);\n }\n body = bodyResult.data;\n }\n\n // Validate query parameters if schema provided\n let query: any = {};\n if (endpoint.querySchema) {\n const queryResult = endpoint.querySchema.safeParse(req.query);\n if (!queryResult.success) {\n return createValidationError(reply, \"query\", queryResult.error);\n }\n query = queryResult.data;\n }\n\n // Validate path parameters if schema provided\n let params: any = {};\n if (endpoint.paramsSchema) {\n const paramsResult = endpoint.paramsSchema.safeParse(req.params);\n if (!paramsResult.success) {\n return createValidationError(reply, \"params\", paramsResult.error);\n }\n params = paramsResult.data;\n }\n\n // Build request object with validated data\n const customRequest: CustomEndpointRequest = {\n body,\n query,\n params,\n headers: req.headers as Record<string, string | string[] | undefined>,\n clientId,\n };\n\n // Merge additional context if provided (e.g., permissions from contextExtractor)\n if (options?.contextExtractor) {\n const additionalContext = await options.contextExtractor(req);\n Object.assign(customRequest, additionalContext);\n }\n\n // Call the user-defined handler with validated and typed data\n const result = await endpoint.handler(customRequest as any);\n\n // Validate response if schema provided\n if (endpoint.responseSchema) {\n const responseResult = endpoint.responseSchema.safeParse(result);\n if (!responseResult.success) {\n // Log the validation error for debugging\n console.error(\n `Response validation failed for ${endpoint.method} ${endpoint.path}:`,\n responseResult.error\n );\n\n // Return generic error to prevent information leakage\n reply.code(500);\n return {\n error: {\n code: \"RESPONSE_VALIDATION_ERROR\",\n message: \"Internal server error: invalid response format\",\n },\n } as EndpointErrorResponse;\n }\n // Return validated response data\n return responseResult.data;\n }\n\n // No response validation - return result as-is\n return result;\n } catch (error) {\n // Handle any errors thrown by the handler\n console.error(\n `Error in custom endpoint ${endpoint.method} ${endpoint.path}:`,\n error\n );\n\n reply.code(500);\n return {\n error: {\n code: \"INTERNAL_ERROR\",\n message:\n error instanceof Error ? error.message : \"Internal server error\",\n },\n } as EndpointErrorResponse;\n }\n });\n }\n}\n\n/**\n * Creates a standardized validation error response.\n * @param reply - Fastify reply object\n * @param field - The field that failed validation\n * @param error - Zod validation error\n * @returns Formatted error response\n */\nexport function createValidationError(\n reply: FastifyReply,\n field: string,\n error: z.ZodError\n): EndpointErrorResponse {\n reply.code(400);\n return {\n error: {\n code: \"VALIDATION_ERROR\",\n message: `Validation failed for ${field}`,\n details: error.errors,\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 { z } from \"zod\";\nimport type { DynamicToolManager } from \"../core/DynamicToolManager.js\";\nimport type { ServerOrchestrator } from \"../core/ServerOrchestrator.js\";\nimport { ClientResourceCache } from \"../session/ClientResourceCache.js\";\nimport type { SessionContextResolver } from \"../session/SessionContextResolver.js\";\nimport type { SessionRequestContext } from \"../types/index.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 {\n FastifyTransportOptions,\n CreateBundleCallback,\n CustomEndpointDefinition,\n} from \"./http.types.js\";\nimport { registerCustomEndpoints } from \"./http.utils.js\";\n\nconst mcpClientIdSchema = z\n .string({ message: \"Missing required mcp-client-id header\" })\n .trim()\n .min(1, \"mcp-client-id header must not be empty\");\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 customEndpoints?: CustomEndpointDefinition[];\n };\n private readonly defaultManager: DynamicToolManager;\n private readonly createBundle: CreateBundleCallback;\n private readonly sessionContextResolver?: SessionContextResolver;\n private readonly baseContext?: unknown;\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 onEvict: (_key, bundle) => {\n // Clean up all sessions when a client bundle is evicted\n this.cleanupBundle(bundle);\n },\n });\n\n constructor(\n defaultManager: DynamicToolManager,\n createBundle: CreateBundleCallback,\n options: FastifyTransportOptions = {},\n configSchema?: object,\n sessionContextResolver?: SessionContextResolver,\n baseContext?: unknown\n ) {\n this.defaultManager = defaultManager;\n this.createBundle = createBundle;\n this.sessionContextResolver = sessionContextResolver;\n this.baseContext = baseContext;\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 customEndpoints: options.customEndpoints,\n };\n this.configSchema = configSchema;\n }\n\n static builder() {\n let _defaultManager: DynamicToolManager;\n let _createBundle: CreateBundleCallback;\n const opts: FastifyTransportOptions = {};\n let _configSchema: object | undefined;\n let _sessionContextResolver: SessionContextResolver | undefined;\n let _baseContext: unknown;\n const builder = {\n defaultManager(value: DynamicToolManager) { _defaultManager = value; return builder; },\n createBundle(value: CreateBundleCallback) { _createBundle = value; return builder; },\n host(value: string) { opts.host = value; return builder; },\n port(value: number) { opts.port = value; return builder; },\n basePath(value: string) { opts.basePath = value; return builder; },\n cors(value: boolean) { opts.cors = value; return builder; },\n logger(value: boolean) { opts.logger = value; return builder; },\n app(value: FastifyInstance) { opts.app = value; return builder; },\n customEndpoints(value: CustomEndpointDefinition[]) { opts.customEndpoints = value; return builder; },\n configSchema(value: object) { _configSchema = value; return builder; },\n sessionContextResolver(value: SessionContextResolver) { _sessionContextResolver = value; return builder; },\n baseContext(value: unknown) { _baseContext = value; return builder; },\n build() { return new FastifyTransport(_defaultManager, _createBundle, opts, _configSchema, _sessionContextResolver, _baseContext); },\n };\n return builder;\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.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 // Register custom endpoints if provided\n if (this.options.customEndpoints && this.options.customEndpoints.length > 0) {\n registerCustomEndpoints(app, base, this.options.customEndpoints);\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 /**\n * @param basePath - The base path to normalize\n * @returns Normalized base path without trailing slash\n */\n private normalizeBasePath(basePath: string): string {\n return basePath.endsWith(\"/\") ? basePath.slice(0, -1) : basePath;\n }\n\n /**\n * @param app - Fastify instance\n * @param base - Base path for routes\n */\n private registerHealthEndpoint(app: FastifyInstance, base: string): void {\n app.get(`${base}/healthz`, async () => ({ ok: true }));\n }\n\n /**\n * @param app - Fastify instance\n * @param base - Base path for routes\n */\n private registerToolsEndpoint(app: FastifyInstance, base: string): void {\n app.get(`${base}/tools`, async () => this.defaultManager.getStatus());\n }\n\n /**\n * @param app - Fastify instance\n * @param base - Base path for routes\n */\n private 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 * @param app - Fastify instance\n * @param base - Base path for routes\n */\n private registerMcpPostEndpoint(app: FastifyInstance, base: string): void {\n app.post(\n `${base}/mcp`,\n async (req: FastifyRequest, reply: FastifyReply) => {\n const parseResult = mcpClientIdSchema.safeParse(\n req.headers[\"mcp-client-id\"]\n );\n if (!parseResult.success) {\n reply.code(400);\n return {\n jsonrpc: \"2.0\",\n error: { code: -32600, message: parseResult.error.issues[0].message },\n id: null,\n };\n }\n const clientId = parseResult.data;\n\n // Build session request context and resolve merged context\n const { cacheKey, mergedContext } = this.resolveSessionContext(\n req,\n clientId\n );\n\n let bundle = this.clientCache.get(cacheKey);\n if (!bundle) {\n const created = this.createBundle(mergedContext);\n bundle = {\n server: created.server,\n orchestrator: created.orchestrator,\n sessions: new Map(),\n };\n this.clientCache.set(cacheKey, 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.body)) {\n await this.drainExistingSessions(bundle.sessions);\n await this.disconnectServer(bundle.server);\n const newSessionId = randomUUID();\n transport = new StreamableHTTPServerTransport({\n sessionIdGenerator: () => newSessionId,\n onsessioninitialized: (sid: string) => {\n bundle!.sessions.set(sid, transport!);\n },\n });\n // Set onclose BEFORE connect() so Protocol.connect() captures it in its\n // chain. SDK 1.26+ wraps the existing onclose alongside _onclose(), so\n // _transport is cleared on disconnect only if this ordering is preserved.\n transport.onclose = () => {\n if (transport?.sessionId)\n bundle!.sessions.delete(transport.sessionId);\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 } 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\n await transport.handleRequest(req.raw, reply.raw, req.body);\n // Fastify will consider the response already sent by transport\n return reply;\n }\n );\n }\n\n /**\n * @param app - Fastify instance\n * @param base - Base path for routes\n */\n private 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 { cacheKey } = this.resolveSessionContext(req, clientId);\n const bundle = this.clientCache.get(cacheKey);\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.raw, reply.raw);\n return reply;\n });\n }\n\n /**\n * @param app - Fastify instance\n * @param base - Base path for routes\n */\n private 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 { cacheKey } = this.resolveSessionContext(req, clientId);\n const bundle = this.clientCache.get(cacheKey);\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 await transport.close();\n } catch {}\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 public async stop(): Promise<void> {\n if (!this.app) return;\n\n // Stop the cache pruning interval and clear all entries (triggers cleanup)\n this.clientCache.stop(true);\n\n if (!this.options.app) {\n await this.app.close();\n }\n this.app = null;\n }\n\n /**\n * Closes all active sessions and clears the session map so the server is\n * free to accept a new connection. Required for SDK 1.26+, which throws\n * \"Already connected\" when `connect()` is called while a transport is\n * still attached. Handles unclean client disconnects followed by re-init.\n *\n * The map is cleared before closing so that `onclose` handlers fired by\n * `transport.close()` do not attempt double-deletion.\n *\n * @param sessions - The client's active session map to drain\n */\n private async drainExistingSessions(\n sessions: Map<string, StreamableHTTPServerTransport>\n ): Promise<void> {\n if (sessions.size === 0) return;\n const existing = Array.from(sessions.values());\n sessions.clear();\n for (const transport of existing) {\n try { await transport.close(); } catch {}\n }\n }\n\n /**\n * Disconnects the server from its current transport so that `Protocol._transport`\n * is cleared before a new connection is established.\n *\n * `drainExistingSessions` handles same-bundle reconnects (sessions in the map).\n * This method handles the STATIC-mode cross-client case: a different client's\n * bundle has an empty sessions map, but the shared server is still attached to\n * the previous client's transport because `StreamableHTTPClientTransport.close()`\n * does not send DELETE—it only aborts connections.\n *\n * @param server - The MCP server to disconnect from its current transport\n */\n private async disconnectServer(server: McpServer): Promise<void> {\n try { await server.close(); } catch {}\n }\n\n /**\n * @param bundle - The client bundle to clean up\n */\n private cleanupBundle(bundle: {\n server: McpServer;\n orchestrator: ServerOrchestrator;\n sessions: Map<string, StreamableHTTPServerTransport>;\n }): void {\n for (const [sessionId, transport] of bundle.sessions.entries()) {\n transport.close().catch((err: unknown) => {\n console.warn(`Error closing session ${sessionId}:`, err);\n });\n }\n bundle.sessions.clear();\n }\n\n /**\n * @param req - The Fastify request\n * @param clientId - The client identifier\n * @returns Object with cache key and merged context\n */\n private resolveSessionContext(\n req: FastifyRequest,\n clientId: string\n ): { cacheKey: string; mergedContext: unknown } {\n // If no session context resolver, use simple clientId cache key\n if (!this.sessionContextResolver) {\n return {\n cacheKey: clientId,\n mergedContext: this.baseContext,\n };\n }\n\n // Build session request context\n const sessionRequestContext: SessionRequestContext = {\n clientId,\n headers: this.extractHeaders(req),\n query: this.extractQuery(req),\n };\n\n // Resolve the merged context\n const result = this.sessionContextResolver.resolve(\n sessionRequestContext,\n this.baseContext\n );\n\n // Build cache key: clientId:suffix\n const cacheKey =\n result.cacheKeySuffix === \"default\"\n ? clientId\n : `${clientId}:${result.cacheKeySuffix}`;\n\n return {\n cacheKey,\n mergedContext: result.context,\n };\n }\n\n /**\n * @param req - The Fastify request\n * @returns Headers as a string record\n */\n private extractHeaders(req: FastifyRequest): Record<string, string> {\n const headers: Record<string, string> = {};\n for (const [key, value] of Object.entries(req.headers)) {\n if (typeof value === \"string\") {\n headers[key.toLowerCase()] = value;\n } else if (Array.isArray(value) && value.length > 0) {\n headers[key.toLowerCase()] = value[0];\n }\n }\n return headers;\n }\n\n /**\n * @param req - The Fastify request\n * @returns Query parameters as a string record\n */\n private extractQuery(req: FastifyRequest): Record<string, string> {\n const query: Record<string, string> = {};\n const rawQuery = req.query as Record<string, unknown>;\n if (rawQuery && typeof rawQuery === \"object\") {\n for (const [key, value] of Object.entries(rawQuery)) {\n if (typeof value === \"string\") {\n query[key] = value;\n }\n }\n }\n return query;\n }\n}\n","import type {\n SessionContextConfig,\n SessionRequestContext,\n} from \"../types/index.js\";\nimport { createHash } from \"node:crypto\";\nimport type { SessionContextResult } from \"./session.types.js\";\n\nexport class SessionContextResolver {\n private readonly config: SessionContextConfig;\n private readonly queryParamName: string;\n private readonly encoding: \"base64\" | \"json\";\n private readonly allowedKeys: Set<string> | null;\n private readonly mergeStrategy: \"shallow\" | \"deep\";\n\n constructor(config: SessionContextConfig) {\n this.config = config;\n this.queryParamName = config.queryParam?.name ?? \"config\";\n this.encoding = config.queryParam?.encoding ?? \"base64\";\n this.allowedKeys = config.queryParam?.allowedKeys\n ? new Set(config.queryParam.allowedKeys)\n : null;\n this.mergeStrategy = config.merge ?? \"shallow\";\n }\n\n static builder() {\n const opts: Partial<SessionContextConfig> = {};\n const builder = {\n enabled(value: boolean) { opts.enabled = value; return builder; },\n queryParam(value: SessionContextConfig[\"queryParam\"]) { opts.queryParam = value; return builder; },\n contextResolver(value: SessionContextConfig[\"contextResolver\"]) { opts.contextResolver = value; return builder; },\n merge(value: \"shallow\" | \"deep\") { opts.merge = value; return builder; },\n build() { return new SessionContextResolver(opts as SessionContextConfig); },\n };\n return builder;\n }\n\n /**\n * @param request - The request context (clientId, headers, query)\n * @param baseContext - The base context from server configuration\n * @returns The resolved context and cache key suffix\n */\n resolve(\n request: SessionRequestContext,\n baseContext: unknown\n ): SessionContextResult {\n // If disabled, return base context with default cache key\n if (this.config.enabled === false) {\n return {\n context: baseContext,\n cacheKeySuffix: \"default\",\n };\n }\n\n const parsedConfig = this.parseQueryConfig(request.query);\n\n if (this.config.contextResolver) {\n return this.resolveWithCustomResolver(request, baseContext, parsedConfig);\n }\n\n return this.resolveWithDefaultMerge(baseContext, parsedConfig);\n }\n\n /**\n * @param request - The request context\n * @param baseContext - The base context from server configuration\n * @param parsedConfig - The parsed query parameter config\n * @returns The resolved context and cache key suffix\n */\n private resolveWithCustomResolver(\n request: SessionRequestContext,\n baseContext: unknown,\n parsedConfig: Record<string, unknown>\n ): SessionContextResult {\n const resolver = this.config.contextResolver;\n if (!resolver) {\n return { context: baseContext, cacheKeySuffix: \"default\" };\n }\n\n try {\n const resolvedContext = resolver(\n request,\n baseContext,\n parsedConfig\n );\n return {\n context: resolvedContext,\n cacheKeySuffix: this.generateCacheKeySuffix(parsedConfig),\n };\n } catch {\n // Fail secure: return base context on resolver error\n return {\n context: baseContext,\n cacheKeySuffix: \"default\",\n };\n }\n }\n\n /**\n * @param baseContext - The base context from server configuration\n * @param parsedConfig - The parsed query parameter config\n * @returns The merged context and cache key suffix\n */\n private resolveWithDefaultMerge(\n baseContext: unknown,\n parsedConfig: Record<string, unknown>\n ): SessionContextResult {\n const mergedContext = this.mergeContexts(baseContext, parsedConfig);\n return {\n context: mergedContext,\n cacheKeySuffix: this.generateCacheKeySuffix(parsedConfig),\n };\n }\n\n /**\n * @param query - Query parameters from the request\n * @returns Parsed and filtered config object\n */\n private parseQueryConfig(\n query: Record<string, string>\n ): Record<string, unknown> {\n const rawValue = query[this.queryParamName];\n if (!rawValue) {\n return {};\n }\n\n try {\n let jsonString: string;\n\n if (this.encoding === \"base64\") {\n // Decode base64 to JSON string\n jsonString = Buffer.from(rawValue, \"base64\").toString(\"utf-8\");\n } else {\n // JSON encoding - value should already be JSON string\n jsonString = rawValue;\n }\n\n const parsed = JSON.parse(jsonString);\n\n // Must be an object\n if (typeof parsed !== \"object\" || parsed === null || Array.isArray(parsed)) {\n return {};\n }\n\n // Filter allowed keys if whitelist is configured\n return this.filterAllowedKeys(parsed);\n } catch {\n // Fail secure: return empty object on any parse error\n return {};\n }\n }\n\n /**\n * @param parsed - The parsed config object\n * @returns Filtered config with only allowed keys\n */\n private filterAllowedKeys(\n parsed: Record<string, unknown>\n ): Record<string, unknown> {\n if (!this.allowedKeys) {\n return parsed;\n }\n\n const filtered: Record<string, unknown> = {};\n for (const key of this.allowedKeys) {\n if (key in parsed) {\n filtered[key] = parsed[key];\n }\n }\n return filtered;\n }\n\n /**\n * @param baseContext - The base context from server configuration\n * @param sessionConfig - The parsed session config\n * @returns Merged context\n */\n private mergeContexts(\n baseContext: unknown,\n sessionConfig: Record<string, unknown>\n ): unknown {\n // If no session config, return base context as-is\n if (Object.keys(sessionConfig).length === 0) {\n return baseContext;\n }\n\n // If base context is not an object, session config takes precedence\n if (\n typeof baseContext !== \"object\" ||\n baseContext === null ||\n Array.isArray(baseContext)\n ) {\n return sessionConfig;\n }\n\n if (this.mergeStrategy === \"deep\") {\n return this.deepMerge(\n baseContext as Record<string, unknown>,\n sessionConfig\n );\n }\n\n // Shallow merge: session config overrides base context\n return {\n ...(baseContext as Record<string, unknown>),\n ...sessionConfig,\n };\n }\n\n /**\n * @param base - The base object\n * @param override - The override object\n * @returns Deep merged object\n */\n private deepMerge(\n base: Record<string, unknown>,\n override: Record<string, unknown>\n ): Record<string, unknown> {\n const result: Record<string, unknown> = { ...base };\n\n for (const [key, value] of Object.entries(override)) {\n const baseValue = result[key];\n\n if (\n typeof value === \"object\" &&\n value !== null &&\n !Array.isArray(value) &&\n typeof baseValue === \"object\" &&\n baseValue !== null &&\n !Array.isArray(baseValue)\n ) {\n // Both are objects - deep merge\n result[key] = this.deepMerge(\n baseValue as Record<string, unknown>,\n value as Record<string, unknown>\n );\n } else {\n // Override base value\n result[key] = value;\n }\n }\n\n return result;\n }\n\n /**\n * @param sessionConfig - The parsed session config\n * @returns Hash string or 'default'\n */\n private generateCacheKeySuffix(\n sessionConfig: Record<string, unknown>\n ): string {\n if (Object.keys(sessionConfig).length === 0) {\n return \"default\";\n }\n\n // Sort keys for deterministic hash\n const sortedKeys = Object.keys(sessionConfig).sort();\n const normalizedObj: Record<string, unknown> = {};\n for (const key of sortedKeys) {\n normalizedObj[key] = sessionConfig[key];\n }\n\n const jsonString = JSON.stringify(normalizedObj);\n return createHash(\"sha256\").update(jsonString).digest(\"hex\").slice(0, 16);\n }\n}\n","import type { SessionContextConfig } from \"../types/index.js\";\n\n/**\n * Validates a session context configuration object to ensure it meets all requirements.\n * Throws descriptive errors for any validation failures.\n *\n * @param config - The session context configuration to validate\n */\nexport function validateSessionContextConfig(config: SessionContextConfig): void {\n validateConfigExists(config);\n validateEnabledField(config);\n validateQueryParamConfig(config);\n validateContextResolver(config);\n validateMergeStrategy(config);\n}\n\n/**\n * @param config - The session context configuration to validate\n */\nfunction validateConfigExists(config: SessionContextConfig): void {\n if (!config || typeof config !== \"object\") {\n throw new Error(\n \"Session context configuration must be an object\"\n );\n }\n}\n\n/**\n * @param config - The session context configuration to validate\n */\nfunction validateEnabledField(config: SessionContextConfig): void {\n if (config.enabled === undefined) {\n return;\n }\n\n if (typeof config.enabled !== \"boolean\") {\n throw new Error(\n `enabled must be a boolean, got ${typeof config.enabled}`\n );\n }\n}\n\n/**\n * @param config - The session context configuration to validate\n */\nfunction validateQueryParamConfig(config: SessionContextConfig): void {\n if (config.queryParam === undefined) {\n return;\n }\n\n if (typeof config.queryParam !== \"object\" || config.queryParam === null) {\n throw new Error(\"queryParam must be an object\");\n }\n\n // Validate name\n if (config.queryParam.name !== undefined) {\n if (\n typeof config.queryParam.name !== \"string\" ||\n config.queryParam.name.length === 0\n ) {\n throw new Error(\"queryParam.name must be a non-empty string\");\n }\n }\n\n // Validate encoding\n if (config.queryParam.encoding !== undefined) {\n if (\n config.queryParam.encoding !== \"base64\" &&\n config.queryParam.encoding !== \"json\"\n ) {\n throw new Error(\n `Invalid queryParam.encoding: \"${config.queryParam.encoding}\". Must be \"base64\" or \"json\"`\n );\n }\n }\n\n // Validate allowedKeys\n if (config.queryParam.allowedKeys !== undefined) {\n if (!Array.isArray(config.queryParam.allowedKeys)) {\n throw new Error(\"queryParam.allowedKeys must be an array of strings\");\n }\n\n for (let i = 0; i < config.queryParam.allowedKeys.length; i++) {\n const key = config.queryParam.allowedKeys[i];\n if (typeof key !== \"string\" || key.length === 0) {\n throw new Error(\n `queryParam.allowedKeys[${i}] must be a non-empty string`\n );\n }\n }\n }\n}\n\n/**\n * @param config - The session context configuration to validate\n */\nfunction validateContextResolver(config: SessionContextConfig): void {\n if (config.contextResolver === undefined) {\n return;\n }\n\n if (typeof config.contextResolver !== \"function\") {\n throw new Error(\n \"contextResolver must be a function: (request, baseContext, parsedQueryConfig?) => unknown\"\n );\n }\n}\n\n/**\n * @param config - The session context configuration to validate\n */\nfunction validateMergeStrategy(config: SessionContextConfig): void {\n if (config.merge === undefined) {\n return;\n }\n\n if (config.merge !== \"shallow\" && config.merge !== \"deep\") {\n throw new Error(\n `Invalid merge strategy: \"${config.merge}\". Must be \"shallow\" or \"deep\"`\n );\n }\n}\n","import { z } from \"zod\";\nimport type { Mode } from \"../types/index.js\";\n\n/**\n * Zod schema for validating startup configuration.\n * Uses strict mode to reject unknown properties like 'initialToolsets'.\n */\nexport const startupConfigSchema = z\n .object({\n mode: z.enum([\"DYNAMIC\", \"STATIC\"]).optional(),\n toolsets: z.union([z.array(z.string()), z.literal(\"ALL\")]).optional(),\n })\n .strict();\n\n/**\n * Validates a startup configuration object against `startupConfigSchema`.\n * Throws a descriptive error when the config is invalid.\n *\n * @param startup - The startup configuration to validate\n */\nexport function validateStartupConfig(\n startup: { mode?: Exclude<Mode, \"ALL\">; toolsets?: string[] | \"ALL\" }\n): void {\n try {\n startupConfigSchema.parse(startup);\n } catch (error) {\n if (error instanceof z.ZodError) {\n const formatted = error.format();\n throw new Error(\n `Invalid startup configuration:\\n${JSON.stringify(formatted, null, 2)}\\n\\n` +\n `Hint: Common mistake - use \"toolsets\" not \"initialToolsets\"`\n );\n }\n throw error;\n }\n}\n\n/**\n * Creates a notifier function that sends `tools/list_changed` notifications\n * to an MCP server. Handles two different notification APIs and suppresses\n * \"Not connected\" errors that occur when no clients are connected.\n *\n * @returns A function that sends tools/list_changed notifications to an MCP server\n */\nexport function createToolsChangedNotifier(): (target: unknown) => Promise<void> {\n type NotifierA = {\n server: { notification: (msg: { method: string }) => Promise<void> | void };\n };\n type NotifierB = { notifyToolsListChanged: () => Promise<void> | void };\n\n const hasNotifierA = (s: unknown): s is NotifierA =>\n typeof (s as NotifierA)?.server?.notification === \"function\";\n const hasNotifierB = (s: unknown): s is NotifierB =>\n typeof (s as NotifierB)?.notifyToolsListChanged === \"function\";\n\n return 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 (err) {\n // Suppress \"Not connected\" errors - expected when no clients are connected\n const errorMessage = err instanceof Error ? err.message : String(err);\n if (errorMessage === \"Not connected\") {\n return; // Silently ignore - no clients to notify\n }\n // Log other errors as they indicate actual problems\n console.warn(\"Failed to send tools list changed notification:\", err);\n }\n };\n}\n\n/**\n * Resolves whether meta-tools should be registered.\n * When `explicit` is provided it takes precedence; otherwise meta-tools are\n * enabled in DYNAMIC mode and disabled in STATIC mode.\n *\n * @param explicit - The user-provided registerMetaTools value (undefined = auto)\n * @param mode - The resolved server mode\n * @returns Whether meta-tools should be registered\n */\nexport function resolveMetaToolsFlag(\n explicit: boolean | undefined,\n mode: Exclude<Mode, \"ALL\">\n): boolean {\n return explicit !== undefined ? explicit : mode === \"DYNAMIC\";\n}\n","import type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport type { Mode } from \"../types/index.js\";\nimport type { CreateBundleCallback } from \"../http/http.types.js\";\nimport type { CreateMcpServerOptions, McpServerHandle } from \"./server.types.js\";\nimport { ServerOrchestrator } from \"../core/ServerOrchestrator.js\";\nimport { FastifyTransport } from \"../http/FastifyTransport.js\";\nimport { SessionContextResolver } from \"../session/SessionContextResolver.js\";\nimport { validateSessionContextConfig } from \"../session/session.utils.js\";\nimport {\n validateStartupConfig,\n createToolsChangedNotifier,\n resolveMetaToolsFlag,\n} from \"./server.utils.js\";\n\nexport type { CreateMcpServerOptions } from \"./server.types.js\";\n\nexport async function createMcpServer(\n options: CreateMcpServerOptions\n): Promise<McpServerHandle> {\n // --- Validate ---\n validateOptions(options);\n\n const mode: Exclude<Mode, \"ALL\"> = options.startup?.mode ?? \"DYNAMIC\";\n const shouldRegisterMetaTools = resolveMetaToolsFlag(options.registerMetaTools, mode);\n const sessionContextResolver = buildSessionContextResolver(options, mode);\n const notifyToolsChanged = createToolsChangedNotifier();\n\n // --- Build base server & orchestrator ---\n const baseServer: McpServer = options.createServer();\n const baseOrchestrator = buildOrchestrator(\n baseServer, options, mode, shouldRegisterMetaTools, notifyToolsChanged\n );\n\n if (mode === \"STATIC\") {\n await baseOrchestrator.ensureReady();\n }\n\n // --- Build transport ---\n const bundleFactory = createBundleFactory(\n options, mode, baseServer, baseOrchestrator, shouldRegisterMetaTools, notifyToolsChanged\n );\n const transport = buildTransport(\n options, baseOrchestrator.getManager(), bundleFactory, sessionContextResolver\n );\n\n return {\n server: baseServer,\n start: () => transport.start(),\n close: () => transport.stop(),\n };\n}\n\n// ---------------------------------------------------------------------------\n// Named helper functions\n// ---------------------------------------------------------------------------\n\n/**\n * Consolidates all upfront validation guards.\n *\n * @param options - Server creation options to validate\n */\nfunction validateOptions(options: CreateMcpServerOptions): void {\n if (options.startup) {\n validateStartupConfig(options.startup);\n }\n if (typeof options.createServer !== \"function\") {\n throw new Error(\"createMcpServer: `createServer` (factory) is required\");\n }\n}\n\n/**\n * Validates session context config, builds the resolver, and warns about\n * limited utility in STATIC mode.\n *\n * @param options - Server creation options containing sessionContext config\n * @param mode - The resolved server mode\n * @returns A SessionContextResolver if configured, otherwise undefined\n */\nfunction buildSessionContextResolver(\n options: CreateMcpServerOptions,\n mode: Exclude<Mode, \"ALL\">\n): SessionContextResolver | undefined {\n if (!options.sessionContext) return undefined;\n\n validateSessionContextConfig(options.sessionContext);\n\n const resolver = SessionContextResolver.builder()\n .enabled(options.sessionContext.enabled ?? true)\n .queryParam(options.sessionContext.queryParam)\n .contextResolver(options.sessionContext.contextResolver)\n .merge(options.sessionContext.merge ?? \"shallow\")\n .build();\n\n if (mode === \"STATIC\" && options.sessionContext.enabled !== false) {\n console.warn(\n \"sessionContext has limited effect in STATIC mode: all clients share the same server instance with base context. \" +\n \"Use DYNAMIC mode for per-session context isolation.\"\n );\n }\n\n return resolver;\n}\n\n/**\n * Builds a ServerOrchestrator with the standard configuration. Used once for\n * the base orchestrator and once per DYNAMIC client.\n *\n * @param server - The MCP server instance\n * @param options - Server creation options (catalog, moduleLoaders, exposurePolicy, startup)\n * @param mode - The resolved server mode\n * @param shouldRegisterMetaTools - Pre-resolved meta-tools flag\n * @param notifyToolsChanged - Notifier function for tool list changes\n * @param context - Optional context override (defaults to options.context)\n * @returns A configured ServerOrchestrator\n */\nfunction buildOrchestrator(\n server: McpServer,\n options: CreateMcpServerOptions,\n mode: Exclude<Mode, \"ALL\">,\n shouldRegisterMetaTools: boolean,\n notifyToolsChanged: (target: unknown) => Promise<void>,\n context?: unknown\n): ServerOrchestrator {\n const builder = ServerOrchestrator.builder()\n .server(server)\n .catalog(options.catalog)\n .moduleLoaders(options.moduleLoaders ?? {})\n .context(context !== undefined ? context : options.context)\n .notifyToolsListChanged(async () => notifyToolsChanged(server))\n .registerMetaTools(shouldRegisterMetaTools);\n\n if (options.exposurePolicy) {\n builder.exposurePolicy(options.exposurePolicy);\n }\n if (options.startup) {\n builder.startup(options.startup);\n }\n\n return builder.build();\n}\n\n/**\n * Creates the bundle factory callback for the transport layer.\n * In STATIC mode all clients share one server + orchestrator.\n * In DYNAMIC mode a fresh server + orchestrator is created per client.\n *\n * @param options - Server creation options\n * @param mode - STATIC reuses base bundle; DYNAMIC creates fresh per client\n * @param baseServer - The shared base server instance\n * @param baseOrchestrator - The shared base orchestrator\n * @param shouldRegisterMetaTools - Pre-resolved meta-tools flag\n * @param notifyToolsChanged - Notifier function for tool list changes\n * @returns Bundle factory callback for the transport layer\n */\nfunction createBundleFactory(\n options: CreateMcpServerOptions,\n mode: Exclude<Mode, \"ALL\">,\n baseServer: McpServer,\n baseOrchestrator: ServerOrchestrator,\n shouldRegisterMetaTools: boolean,\n notifyToolsChanged: (target: unknown) => Promise<void>\n): CreateBundleCallback {\n return (mergedContext?: unknown) => {\n if (mode === \"STATIC\") {\n // STATIC: all clients share one server + orchestrator\n return { server: baseServer, orchestrator: baseOrchestrator };\n }\n\n // DYNAMIC: fresh server + orchestrator per client\n const effectiveContext = mergedContext ?? options.context;\n const clientServer: McpServer = options.createServer();\n const clientOrchestrator = buildOrchestrator(\n clientServer, options, mode, shouldRegisterMetaTools, notifyToolsChanged, effectiveContext\n );\n return { server: clientServer, orchestrator: clientOrchestrator };\n };\n}\n\n/**\n * Builds the FastifyTransport using the builder pattern, handling conditional\n * `.app()`, `.customEndpoints()`, `.sessionContextResolver()`, and `.baseContext()` chaining.\n *\n * @param options - Server creation options (http, configSchema, context)\n * @param manager - Default DynamicToolManager for status endpoints\n * @param bundleFactory - Bundle factory callback for the transport layer\n * @param sessionContextResolver - Optional session context resolver\n * @returns A configured FastifyTransport\n */\nfunction buildTransport(\n options: CreateMcpServerOptions,\n manager: ReturnType<ServerOrchestrator[\"getManager\"]>,\n bundleFactory: CreateBundleCallback,\n sessionContextResolver: SessionContextResolver | undefined\n): FastifyTransport {\n const builder = FastifyTransport.builder()\n .defaultManager(manager)\n .createBundle(bundleFactory)\n .host(options.http?.host ?? \"0.0.0.0\")\n .port(options.http?.port ?? 3000)\n .basePath(options.http?.basePath ?? \"/\")\n .cors(options.http?.cors ?? true)\n .logger(options.http?.logger ?? false);\n\n if (options.http?.app) {\n builder.app(options.http.app);\n }\n if (options.http?.customEndpoints) {\n builder.customEndpoints(options.http.customEndpoints);\n }\n if (options.configSchema) {\n builder.configSchema(options.configSchema);\n }\n if (sessionContextResolver) {\n builder.sessionContextResolver(sessionContextResolver);\n }\n if (options.context !== undefined) {\n builder.baseContext(options.context);\n }\n\n return builder.build();\n}\n","import type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport type { ExposurePolicy, PermissionConfig } from \"../types/index.js\";\nimport type { ServerOrchestrator } from \"../core/ServerOrchestrator.js\";\nimport type { PermissionResolver } from \"./PermissionResolver.js\";\nimport type {\n ClientRequestContext,\n PermissionAwareBundle,\n} from \"./permissions.types.js\";\n\n// --- Validation functions (from validatePermissionConfig.ts) ---\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 */\nexport function validatePermissionConfig(config: PermissionConfig): void {\n validateConfigExists(config);\n validateSourceField(config);\n validateConfigBasedPermissions(config);\n validateTypes(config);\n}\n\n/**\n * @param config - The permission configuration to validate\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 * @param config - The permission configuration to validate\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 * @param config - The permission configuration to validate\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 * @param config - The permission configuration to validate\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 * @param staticMap - The static map to validate\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\n// --- createPermissionAwareBundle (from createPermissionAwareBundle.ts) ---\n\n/**\n * Creates a permission-aware bundle creation function that wraps the original\n * createBundle function with permission resolution and enforcement.\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 return async (\n context: ClientRequestContext\n ): Promise<PermissionAwareBundle> => {\n // Resolve permissions for this client\n const requestedToolsets = 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(requestedToolsets);\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\n const enabledToolsets: string[] = [];\n const failedToolsets: string[] = [];\n\n if (requestedToolsets.length > 0) {\n const result = await manager.enableToolsets(requestedToolsets);\n\n // Collect successful and failed toolsets\n for (const r of result.results) {\n if (r.success) {\n enabledToolsets.push(r.name);\n } else {\n failedToolsets.push(r.name);\n console.warn(\n `Failed to enable toolset '${r.name}' for client '${context.clientId}': ${r.message}`\n );\n }\n }\n\n // If ALL toolsets failed, this is likely a configuration error\n if (enabledToolsets.length === 0 && failedToolsets.length > 0) {\n throw new Error(\n `All requested toolsets failed to enable for client '${context.clientId}'. ` +\n `Requested: [${requestedToolsets.join(\", \")}]. ` +\n `Check that toolset names in permissions match the catalog.`\n );\n }\n }\n\n // Return bundle with resolved permissions\n return {\n server: bundle.server,\n orchestrator: bundle.orchestrator,\n allowedToolsets: enabledToolsets,\n failedToolsets,\n };\n };\n}\n\n// --- sanitizeExposurePolicyForPermissions (from createPermissionBasedMcpServer.ts) ---\n\n/**\n * Validates and sanitizes exposure policy for permission-based servers.\n * Certain policy options are not applicable or could conflict with permission-based access control.\n * @param policy - The original exposure policy\n * @returns Sanitized policy safe for permission-based servers\n */\nexport function sanitizeExposurePolicyForPermissions(\n policy?: ExposurePolicy\n): ExposurePolicy | undefined {\n if (!policy) return undefined;\n\n const sanitized: ExposurePolicy = {\n namespaceToolsWithSetKey: policy.namespaceToolsWithSetKey,\n };\n\n // Warn about ignored options\n if (policy.allowlist !== undefined) {\n console.warn(\n \"Permission-based servers: exposurePolicy.allowlist is ignored. \" +\n \"Allowed toolsets are determined by client permissions.\"\n );\n }\n if (policy.denylist !== undefined) {\n console.warn(\n \"Permission-based servers: exposurePolicy.denylist is ignored. \" +\n \"Use permission configuration to control toolset access.\"\n );\n }\n if (policy.maxActiveToolsets !== undefined) {\n console.warn(\n \"Permission-based servers: exposurePolicy.maxActiveToolsets is ignored. \" +\n \"Toolset count is determined by client permissions.\"\n );\n }\n if (policy.onLimitExceeded !== undefined) {\n console.warn(\n \"Permission-based servers: exposurePolicy.onLimitExceeded is ignored. \" +\n \"No toolset limits are enforced.\"\n );\n }\n\n return sanitized;\n}\n","import type { PermissionConfig } from \"../types/index.js\";\n\nexport class PermissionResolver {\n private cache = new Map<string, string[]>();\n private readonly normalizedHeaderName: string;\n\n constructor(private config: PermissionConfig) {\n // Pre-normalize header name to lowercase for case-insensitive matching\n this.normalizedHeaderName = (\n config.headerName || \"mcp-toolset-permissions\"\n ).toLowerCase();\n }\n\n static builder() {\n const opts: Partial<PermissionConfig> = {};\n const builder = {\n source(value: \"headers\" | \"config\") { opts.source = value; return builder; },\n headerName(value: string) { opts.headerName = value; return builder; },\n staticMap(value: Record<string, string[]>) { opts.staticMap = value; return builder; },\n resolver(value: (clientId: string) => string[]) { opts.resolver = value; return builder; },\n defaultPermissions(value: string[]) { opts.defaultPermissions = value; return builder; },\n build() { return new PermissionResolver(opts as PermissionConfig); },\n };\n return builder;\n }\n\n /**\n * @param clientId - The unique identifier for the client\n * @param headers - Optional request headers\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 * @param clientId - The client ID to invalidate\n */\n invalidateCache(clientId: string): void {\n this.cache.delete(clientId);\n }\n\n /**\n * @param headers - Request headers containing permission data\n * @returns Array of toolset names from headers\n */\n #parseHeaderPermissions(headers?: Record<string, string>): string[] {\n if (!headers) {\n return [];\n }\n\n // Find header value using case-insensitive lookup\n const headerValue = this.#findHeaderCaseInsensitive(\n headers,\n this.normalizedHeaderName\n );\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 '${this.normalizedHeaderName}':`,\n error\n );\n return [];\n }\n }\n\n /**\n * @param headers - The headers object to search\n * @param normalizedKey - The lowercase key to search for\n * @returns The header value if found\n */\n #findHeaderCaseInsensitive(\n headers: Record<string, string>,\n normalizedKey: string\n ): string | undefined {\n // Fast path: check if key exists as-is (common case with Fastify's lowercased headers)\n if (headers[normalizedKey] !== undefined) {\n return headers[normalizedKey];\n }\n // Slow path: iterate and compare lowercase\n for (const [key, value] of Object.entries(headers)) {\n if (key.toLowerCase() === normalizedKey) {\n return value;\n }\n }\n return undefined;\n }\n\n /**\n * @param clientId - The unique identifier for the client\n * @returns Array of toolset names from configuration\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 * @param clientId - The unique identifier for the client\n * @returns Array of toolset names if successful, null if resolver fails\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 * @param clientId - The unique identifier for the client\n * @returns Array of toolset names if found, null if client not in map\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 clearCache(): void {\n this.cache.clear();\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 { z } from \"zod\";\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 PermissionAwareFastifyTransportOptions,\n} from \"./permissions.types.js\";\nimport type { CustomEndpointDefinition } from \"../http/http.types.js\";\nimport { registerCustomEndpoints } from \"../http/http.utils.js\";\n\nconst mcpClientIdSchema = z\n .string({ message: \"Missing required mcp-client-id header\" })\n .trim()\n .min(1, \"mcp-client-id header must not be empty\");\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 customEndpoints?: CustomEndpointDefinition[];\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 failedToolsets: string[];\n }>({\n onEvict: (_key, bundle) => {\n // Clean up all sessions when a client bundle is evicted\n this.#cleanupBundle(bundle);\n },\n });\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 customEndpoints: options.customEndpoints,\n };\n this.configSchema = configSchema;\n }\n\n static builder() {\n let _defaultManager: DynamicToolManager;\n let _createPermissionAwareBundle: (context: ClientRequestContext) => Promise<PermissionAwareBundle>;\n const opts: PermissionAwareFastifyTransportOptions = {};\n let _configSchema: object | undefined;\n const builder = {\n defaultManager(value: DynamicToolManager) { _defaultManager = value; return builder; },\n createPermissionAwareBundle(value: (context: ClientRequestContext) => Promise<PermissionAwareBundle>) { _createPermissionAwareBundle = value; return builder; },\n host(value: string) { opts.host = value; return builder; },\n port(value: number) { opts.port = value; return builder; },\n basePath(value: string) { opts.basePath = value; return builder; },\n cors(value: boolean) { opts.cors = value; return builder; },\n logger(value: boolean) { opts.logger = value; return builder; },\n app(value: FastifyInstance) { opts.app = value; return builder; },\n customEndpoints(value: CustomEndpointDefinition[]) { opts.customEndpoints = value; return builder; },\n configSchema(value: object) { _configSchema = value; return builder; },\n build() { return new PermissionAwareFastifyTransport(_defaultManager, _createPermissionAwareBundle, opts, _configSchema); },\n };\n return builder;\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.#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 // Register custom endpoints if provided with permission context\n // IMPORTANT: Only register if customEndpoints is provided AND has items\n if (this.options.customEndpoints && this.options.customEndpoints.length > 0) {\n registerCustomEndpoints(app, base, this.options.customEndpoints, {\n contextExtractor: async (req) => {\n // Extract client context from request\n const context = this.#extractClientContext(req);\n\n // Resolve permissions for this client\n try {\n const bundle = await this.createPermissionAwareBundle(context);\n return {\n allowedToolsets: bundle.allowedToolsets,\n failedToolsets: bundle.failedToolsets,\n };\n } catch (error) {\n // If permission resolution fails, return empty permissions\n console.warn(\n `Permission resolution failed for custom endpoint: ${error}`\n );\n return {\n allowedToolsets: [],\n failedToolsets: [],\n };\n }\n },\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\n // Stop the cache pruning interval and clear all entries (triggers cleanup)\n this.clientCache.stop(true);\n\n if (!this.options.app) {\n await this.app.close();\n }\n this.app = null;\n }\n\n /**\n * Closes all active sessions and clears the session map so the server is\n * free to accept a new connection. Required for SDK 1.26+, which throws\n * \"Already connected\" when `connect()` is called while a transport is\n * still attached. Handles unclean client disconnects followed by re-init.\n *\n * The map is cleared before closing so that `onclose` handlers fired by\n * `transport.close()` do not attempt double-deletion.\n *\n * @param sessions - The client's active session map to drain\n */\n async #drainExistingSessions(\n sessions: Map<string, StreamableHTTPServerTransport>\n ): Promise<void> {\n if (sessions.size === 0) return;\n const existing = Array.from(sessions.values());\n sessions.clear();\n for (const transport of existing) {\n try { await transport.close(); } catch {}\n }\n }\n\n /**\n * Disconnects the server from its current transport so that `Protocol._transport`\n * is cleared before a new connection is established.\n *\n * `#drainExistingSessions` handles same-bundle reconnects (sessions in the map).\n * This method handles the case where the same client reconnects after\n * `StreamableHTTPClientTransport.close()` aborted the connection without\n * sending DELETE, leaving the server still attached to the old transport.\n *\n * @param server - The MCP server to disconnect from its current transport\n */\n async #disconnectServer(server: McpServer): Promise<void> {\n try { await server.close(); } catch {}\n }\n\n /**\n * @param bundle - The client bundle to clean up\n */\n #cleanupBundle(bundle: {\n server: McpServer;\n orchestrator: ServerOrchestrator;\n sessions: Map<string, StreamableHTTPServerTransport>;\n allowedToolsets: string[];\n failedToolsets: string[];\n }): void {\n for (const [sessionId, transport] of bundle.sessions.entries()) {\n transport.close().catch((err: unknown) => {\n console.warn(`Error closing session ${sessionId}:`, err);\n });\n }\n bundle.sessions.clear();\n }\n\n /**\n * @param basePath - The base path to normalize\n * @returns Normalized base path without trailing slash\n */\n #normalizeBasePath(basePath: string): string {\n return basePath.endsWith(\"/\") ? basePath.slice(0, -1) : basePath;\n }\n\n /**\n * @param app - Fastify instance\n * @param base - Base path for routes\n */\n #registerHealthEndpoint(app: FastifyInstance, base: string): void {\n app.get(`${base}/healthz`, async () => ({ ok: true }));\n }\n\n /**\n * @param app - Fastify instance\n * @param base - Base path for routes\n */\n #registerToolsEndpoint(app: FastifyInstance, base: string): void {\n app.get(`${base}/tools`, async () => this.defaultManager.getStatus());\n }\n\n /**\n * @param app - Fastify instance\n * @param base - Base path for routes\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 * @param app - Fastify instance\n * @param base - Base path for routes\n */\n #registerMcpPostEndpoint(app: FastifyInstance, base: string): void {\n app.post(\n `${base}/mcp`,\n async (req: FastifyRequest, reply: FastifyReply) => {\n // Validate mcp-client-id header\n const parseResult = mcpClientIdSchema.safeParse(\n req.headers[\"mcp-client-id\"]\n );\n if (!parseResult.success) {\n reply.code(400);\n return {\n jsonrpc: \"2.0\",\n error: { code: -32600, message: parseResult.error.issues[0].message },\n id: null,\n };\n }\n\n // Extract client context from request\n const context = this.#extractClientContext(req);\n\n // Get or create permission-aware bundle for this client\n let bundle = this.clientCache.get(context.clientId);\n if (!bundle) {\n try {\n const created = await this.createPermissionAwareBundle(context);\n\n // Log any failed toolsets for debugging\n if (created.failedToolsets.length > 0) {\n console.warn(\n `Client ${context.clientId} had ${created.failedToolsets.length} toolsets fail to enable: ` +\n `[${created.failedToolsets.join(\", \")}]. ` +\n `Successfully enabled: [${created.allowedToolsets.join(\", \")}]`\n );\n }\n\n const providedSessions = (created as { sessions?: Map<string, StreamableHTTPServerTransport> }).sessions;\n bundle = {\n server: created.server,\n orchestrator: created.orchestrator,\n allowedToolsets: created.allowedToolsets,\n failedToolsets: created.failedToolsets,\n sessions:\n providedSessions instanceof Map ? providedSessions : new Map(),\n };\n 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.body)) {\n await this.#drainExistingSessions(bundle.sessions);\n await this.#disconnectServer(bundle.server);\n const newSessionId = randomUUID();\n transport = new StreamableHTTPServerTransport({\n sessionIdGenerator: () => newSessionId,\n onsessioninitialized: (sid: string) => {\n bundle!.sessions.set(sid, transport!);\n },\n });\n // Set onclose BEFORE connect() so Protocol.connect() captures it in its\n // chain. SDK 1.26+ wraps the existing onclose alongside _onclose(), so\n // _transport is cleared on disconnect only if this ordering is preserved.\n transport.onclose = () => {\n if (transport?.sessionId)\n bundle!.sessions.delete(transport.sessionId);\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 } 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\n await transport.handleRequest(req.raw, reply.raw, req.body);\n return reply;\n }\n );\n }\n\n /**\n * @param app - Fastify instance\n * @param base - Base path for routes\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.raw, reply.raw);\n return reply;\n });\n }\n\n /**\n * @param app - Fastify instance\n * @param base - Base path for routes\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 await transport.close();\n } catch {}\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 * @param req - Fastify request object\n * @returns Client request context with ID and headers\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 * @param message - Generic error message to return to client\n * @param code - JSON-RPC error code\n * @returns JSON-RPC error response object\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 { ExposurePolicy } from \"../types/index.js\";\nimport type {\n CreatePermissionBasedMcpServerOptions,\n McpServerHandle,\n} from \"./server.types.js\";\nimport {\n validatePermissionConfig,\n createPermissionAwareBundle,\n sanitizeExposurePolicyForPermissions,\n} from \"../permissions/permissions.utils.js\";\nimport { validateSessionContextConfig } from \"../session/session.utils.js\";\nimport { PermissionResolver } from \"../permissions/PermissionResolver.js\";\nimport { ServerOrchestrator } from \"../core/ServerOrchestrator.js\";\nimport { PermissionAwareFastifyTransport } from \"../permissions/PermissionAwareFastifyTransport.js\";\n\nexport async function createPermissionBasedMcpServer(\n options: CreatePermissionBasedMcpServerOptions\n): Promise<McpServerHandle> {\n // --- Validate ---\n validatePermissionOptions(options);\n\n const sanitizedPolicy = sanitizeExposurePolicyForPermissions(options.exposurePolicy);\n const permissionResolver = buildPermissionResolver(options);\n\n // --- Base server & status-only orchestrator ---\n const baseServer: McpServer = options.createServer();\n const baseOrchestrator = buildPermissionOrchestrator(baseServer, options, sanitizedPolicy);\n\n // --- Per-client bundle factory ---\n const createBundle = createPermissionAwareBundle(\n createClientOrchestratorFactory(options, sanitizedPolicy),\n permissionResolver\n );\n\n // --- Transport ---\n const transport = buildPermissionTransport(options, baseOrchestrator.getManager(), createBundle);\n\n return {\n server: baseServer,\n start: () => transport.start(),\n close: async () => {\n try {\n await transport.stop();\n } finally {\n permissionResolver.clearCache();\n }\n },\n };\n}\n\n// ---------------------------------------------------------------------------\n// Named helper functions\n// ---------------------------------------------------------------------------\n\n/**\n * Consolidates all upfront validation guards for permission-based servers.\n *\n * @param options - Server creation options to validate\n */\nfunction validatePermissionOptions(\n options: CreatePermissionBasedMcpServerOptions\n): void {\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 validatePermissionConfig(options.permissions);\n\n if (options.sessionContext) {\n validateSessionContextConfig(options.sessionContext);\n console.warn(\n \"Session context support for permission-based servers is limited. \" +\n \"The base context will be used for module loaders.\"\n );\n }\n\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 if (typeof options.createServer !== \"function\") {\n throw new Error(\n \"createPermissionBasedMcpServer: `createServer` (factory) is required\"\n );\n }\n}\n\n/**\n * Builds a PermissionResolver from the options config.\n *\n * @param options - Server creation options containing permission config\n * @returns A configured PermissionResolver\n */\nfunction buildPermissionResolver(\n options: CreatePermissionBasedMcpServerOptions\n): PermissionResolver {\n const builder = PermissionResolver.builder()\n .source(options.permissions.source)\n .headerName(options.permissions.headerName ?? \"mcp-toolset-permissions\")\n .staticMap(options.permissions.staticMap ?? {})\n .defaultPermissions(options.permissions.defaultPermissions ?? []);\n\n if (options.permissions.resolver) {\n builder.resolver(options.permissions.resolver);\n }\n\n return builder.build();\n}\n\n/**\n * Builds a ServerOrchestrator configured for permission-based operation\n * (STATIC mode, empty toolsets, no meta-tools, no notifier).\n *\n * @param server - The MCP server instance\n * @param options - Server creation options (catalog, moduleLoaders, context)\n * @param policy - Sanitized exposure policy\n * @returns Orchestrator configured for permission-based operation\n */\nfunction buildPermissionOrchestrator(\n server: McpServer,\n options: CreatePermissionBasedMcpServerOptions,\n policy: ExposurePolicy | undefined\n): ServerOrchestrator {\n const builder = ServerOrchestrator.builder()\n .server(server)\n .catalog(options.catalog)\n .moduleLoaders(options.moduleLoaders ?? {})\n .context(options.context)\n .startup({ mode: \"STATIC\", toolsets: [] })\n .registerMetaTools(false);\n\n if (policy) {\n builder.exposurePolicy(policy);\n }\n\n return builder.build();\n}\n\n/**\n * Creates the callback that produces a fresh server + orchestrator per client,\n * scoped to the client's allowed toolsets.\n *\n * @param options - Server creation options\n * @param policy - Sanitized exposure policy\n * @returns Factory callback that accepts allowed toolsets and returns a server/orchestrator pair\n */\nfunction createClientOrchestratorFactory(\n options: CreatePermissionBasedMcpServerOptions,\n policy: ExposurePolicy | undefined\n): (allowedToolsets: string[]) => { server: McpServer; orchestrator: ServerOrchestrator } {\n return (allowedToolsets: string[]) => {\n const clientServer: McpServer = options.createServer();\n const clientOrchestrator = buildPermissionOrchestrator(clientServer, options, policy);\n return { server: clientServer, orchestrator: clientOrchestrator };\n };\n}\n\n/**\n * Builds the PermissionAwareFastifyTransport, handling conditional `.app()`\n * and `.customEndpoints()` chaining.\n *\n * @param options - Server creation options (http config)\n * @param manager - Default DynamicToolManager for status endpoints\n * @param createBundle - Permission-aware bundle creator\n * @returns A configured PermissionAwareFastifyTransport\n */\nfunction buildPermissionTransport(\n options: CreatePermissionBasedMcpServerOptions,\n manager: ReturnType<ServerOrchestrator[\"getManager\"]>,\n createBundle: ReturnType<typeof createPermissionAwareBundle>\n): PermissionAwareFastifyTransport {\n const builder = PermissionAwareFastifyTransport.builder()\n .defaultManager(manager)\n .createPermissionAwareBundle(createBundle)\n .host(options.http?.host ?? \"0.0.0.0\")\n .port(options.http?.port ?? 3000)\n .basePath(options.http?.basePath ?? \"/\")\n .cors(options.http?.cors ?? true)\n .logger(options.http?.logger ?? false);\n\n if (options.http?.app) {\n builder.app(options.http.app);\n }\n if (options.http?.customEndpoints) {\n builder.customEndpoints(options.http.customEndpoints);\n }\n if (options.configSchema) {\n builder.configSchema(options.configSchema);\n }\n\n return builder.build();\n}\n"],"names":["DEFAULT_KEYS","RESERVED_TOOLSET_KEYS","ToolsetValidator","options","__publicField","opts","builder","value","env","args","input","catalog","raw","s","valid","result","name","toolsets","modules","def","m","sanitized","available","toolsetNames","error","source","key","ModuleResolver","context","collected","toolsetName","modKey","loader","loaded","err","ToolingError","message","code","details","_options","ToolRegistry","toolsetKey","toolName","set","tools","t","safe","k","v","DynamicToolManager","skipNotification","validation","policyCheck","registeredTools","toolCount","resolvedTools","mapped","tool","activeToolsets","results","res","successAll","r","anySuccess","all","META_TOOLSET_KEY","registerMetaTools","server","manager","toolRegistry","z","byToolset","items","payload","status","ServerOrchestrator","startup","resolved","managerBuilder","initial","mode","names","isValid","_ClientResourceCache","__privateAdd","_ClientResourceCache_instances","pruneEvery","entry","resource","newEntry","__privateMethod","callEvictCallback_fn","clearEntries","entries","lruKey","now","keysToDelete","ClientResourceCache","defineEndpoint","definition","definePermissionAwareEndpoint","registerCustomEndpoints","app","basePath","endpoints","reservedPaths","endpoint","fullPath","reserved","method","req","reply","clientIdHeader","clientId","randomUUID","body","bodyResult","createValidationError","query","queryResult","params","paramsResult","customRequest","additionalContext","responseResult","field","mcpClientIdSchema","FastifyTransport","defaultManager","createBundle","configSchema","sessionContextResolver","baseContext","_key","bundle","_defaultManager","_createBundle","_configSchema","_sessionContextResolver","_baseContext","Fastify","cors","base","_req","parseResult","cacheKey","mergedContext","created","sessionId","transport","isInitializeRequest","newSessionId","StreamableHTTPServerTransport","sid","sessions","existing","sessionRequestContext","headers","rawQuery","SessionContextResolver","config","request","parsedConfig","resolver","rawValue","jsonString","parsed","filtered","sessionConfig","override","baseValue","sortedKeys","normalizedObj","createHash","validateSessionContextConfig","validateConfigExists","validateEnabledField","validateQueryParamConfig","validateContextResolver","validateMergeStrategy","i","startupConfigSchema","validateStartupConfig","formatted","createToolsChangedNotifier","hasNotifierA","hasNotifierB","target","resolveMetaToolsFlag","explicit","createMcpServer","validateOptions","shouldRegisterMetaTools","buildSessionContextResolver","notifyToolsChanged","baseServer","baseOrchestrator","buildOrchestrator","bundleFactory","createBundleFactory","buildTransport","effectiveContext","clientServer","clientOrchestrator","validatePermissionConfig","validateSourceField","validateConfigBasedPermissions","validateTypes","validateStaticMapValues","staticMap","permissions","createPermissionAwareBundle","originalCreateBundle","permissionResolver","requestedToolsets","enabledToolsets","failedToolsets","sanitizeExposurePolicyForPermissions","policy","_PermissionResolver","_PermissionResolver_instances","parseHeaderPermissions_fn","resolveConfigPermissions_fn","headerValue","findHeaderCaseInsensitive_fn","normalizedKey","resolverResult","tryResolverFunction_fn","staticResult","lookupStaticMap_fn","PermissionResolver","_PermissionAwareFastifyTransport","_PermissionAwareFastifyTransport_instances","cleanupBundle_fn","_createPermissionAwareBundle","normalizeBasePath_fn","registerHealthEndpoint_fn","registerToolsEndpoint_fn","registerConfigDiscoveryEndpoint_fn","registerMcpPostEndpoint_fn","registerMcpGetEndpoint_fn","registerMcpDeleteEndpoint_fn","extractClientContext_fn","drainExistingSessions_fn","disconnectServer_fn","providedSessions","createSafeErrorResponse_fn","PermissionAwareFastifyTransport","createPermissionBasedMcpServer","validatePermissionOptions","sanitizedPolicy","buildPermissionResolver","buildPermissionOrchestrator","createClientOrchestratorFactory","buildPermissionTransport","allowedToolsets"],"mappings":"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"}