import { type Tool as McpTool } from '@modelcontextprotocol/sdk/types.js'; import { type ToolResponse } from '../core/response.js'; import { type ToolBuilder } from '../core/types.js'; import { type ProgressSink } from '../core/execution/ProgressHelper.js'; import { type DebugObserverFn } from '../observability/DebugObserver.js'; import { type FusionTracer } from '../observability/Tracing.js'; import { type StateSyncConfig } from '../state-sync/types.js'; import { type IntrospectionConfig } from '../introspection/types.js'; import { type ZeroTrustConfig } from '../introspection/CryptoAttestation.js'; import { type SelfHealingConfig } from '../introspection/ContractAwareSelfHealing.js'; import { type ToolExposition } from '../exposition/types.js'; import { type PromptRegistry } from '../prompt/PromptRegistry.js'; import { StateMachineGate, type FsmStateStore } from '../fsm/StateMachineGate.js'; import type { TelemetrySink } from '../observability/TelemetryEvent.js'; /** Options for attaching to an MCP Server */ export interface AttachOptions { /** Only expose tools matching these tag filters */ filter?: { tags?: string[]; anyTag?: string[]; exclude?: string[]; }; /** * Factory function to create a per-request context. * Receives the MCP `extra` object (session info, meta, etc.). * If omitted, `undefined` is used as context (suitable for `ToolRegistry`). * Supports async factories (e.g. for token verification, DB connection). */ contextFactory?: (extra: unknown) => TContext | Promise; /** * Enable debug observability for ALL registered tools. * * When set, the observer is automatically propagated to every tool * builder, and registry-level routing events are also emitted. * * @example * ```typescript * registry.attachToServer(server, { * contextFactory: createContext, * debug: createDebugObserver(), * }); * ``` * * @see {@link createDebugObserver} for creating an observer */ debug?: DebugObserverFn; /** * Enable State Sync to prevent LLM Temporal Blindness and Causal State Drift. * * When configured, Fusion automatically: * 1. Appends `[Cache-Control: X]` to tool descriptions during `tools/list` * 2. Prepends `[System: Cache invalidated...]` after successful mutations in `tools/call` * * Zero overhead when omitted — no state-sync code runs. * * @example * ```typescript * registry.attachToServer(server, { * contextFactory: createContext, * stateSync: { * defaults: { cacheControl: 'no-store' }, * policies: [ * { match: 'sprints.update', invalidates: ['sprints.*'] }, * { match: 'tasks.update', invalidates: ['tasks.*', 'sprints.*'] }, * { match: 'countries.*', cacheControl: 'immutable' }, * ], * }, * }); * ``` * * @see {@link StateSyncConfig} for configuration options * @see {@link https://arxiv.org/abs/2510.23853 | "Your LLM Agents are Temporally Blind"} */ stateSync?: StateSyncConfig; /** * Enable dynamic introspection manifest (MCP Resource). * * When enabled, the framework registers a `resources/list` and * `resources/read` handler exposing a structured manifest of all * registered tools, actions, and presenters. * * **Security**: Opt-in only. Never enabled silently. * **RBAC**: The `filter` callback allows dynamic per-session * manifest filtering. Unauthorized agents never see hidden tools. * * @example * ```typescript * registry.attachToServer(server, { * contextFactory: createContext, * introspection: { * enabled: process.env.NODE_ENV !== 'production', * uri: 'fusion://manifest.json', * filter: (manifest, ctx) => { * if (ctx.user.role !== 'admin') { * delete manifest.capabilities.tools['admin.delete_user']; * } * return manifest; * }, * }, * }); * ``` * * @see {@link IntrospectionConfig} for configuration options */ introspection?: IntrospectionConfig; /** * Enable OpenTelemetry-compatible tracing for ALL registered tools. * * When set, the tracer is automatically propagated to every tool * builder, and registry-level routing spans are also created. * * **Context propagation limitation**: Since MCP Fusion does not depend * on `@opentelemetry/api`, it cannot call `context.with(trace.setSpan(...))`. * Auto-instrumented downstream calls (Prisma, HTTP, Redis) inside tool * handlers will appear as **siblings**, not children, of the MCP span. * This is an intentional trade-off for zero runtime dependencies. * * @example * ```typescript * import { trace } from '@opentelemetry/api'; * * registry.attachToServer(server, { * contextFactory: createContext, * tracing: trace.getTracer('mcp-fusion'), * }); * ``` * * @see {@link FusionTracer} for the tracer interface contract */ tracing?: FusionTracer; /** * Telemetry sink for the Inspector TUI. * * When set, emits `route`, `execute`, and `error` events for each * tool call, enabling the real-time TUI dashboard. * * Zero overhead when omitted. */ telemetry?: TelemetrySink; /** * Server name used in the introspection manifest. * @defaultValue `'mcp-fusion-server'` */ serverName?: string; /** * Exposition strategy for projecting grouped tools onto the MCP wire format. * * - `'flat'` (default): Each action becomes an independent atomic MCP tool. * Guarantees privilege isolation, deterministic routing, and granular UI. * Example: `projects_list`, `projects_create` — two separate buttons in Claude. * * - `'grouped'`: All actions within a builder are merged into a single MCP * tool with a discriminated-union schema (legacy behavior). * * @default 'flat' * * @example * ```typescript * registry.attachToServer(server, { * contextFactory: createContext, * toolExposition: 'flat', // Each action = 1 MCP tool * actionSeparator: '_', // projects_list, projects_create * }); * ``` * * @see {@link ToolExposition} for strategy details */ toolExposition?: ToolExposition; /** * Delimiter for deterministic naming interpolation in flat mode. * Used to join `{toolName}{separator}{actionKey}`. * * @default '_' * * @example * ```typescript * // '_' → projects_list, projects_create * // '.' → projects.list, projects.create * // '-' → projects-list, projects-create * ``` */ actionSeparator?: string; /** * Prompt registry for server-side hydrated prompts. * * When provided, the framework registers `prompts/list` and * `prompts/get` handlers on the MCP server, enabling slash * command discovery and Zero-Shot Context hydration. * * Zero overhead when omitted — no prompt code runs. * * @example * ```typescript * const promptRegistry = new PromptRegistry(); * promptRegistry.register(AuditPrompt); * * registry.attachToServer(server, { * contextFactory: createContext, * prompts: promptRegistry, * }); * ``` * * @see {@link PromptRegistry} for prompt registration * @see {@link definePrompt} for creating prompts */ prompts?: PromptRegistry; /** * Enable Zero-Trust runtime verification for behavioral contracts. * * When configured, the framework: * 1. Materializes ToolContracts from all registered builders * 2. Computes a server-level behavioral digest * 3. Optionally verifies against a known-good digest (capability pinning) * 4. Exposes the trust capability via MCP server metadata * * Zero overhead when omitted — no cryptographic operations run. * * @example * ```typescript * registry.attachToServer(server, { * contextFactory: createContext, * zeroTrust: { * signer: 'hmac', * secret: process.env.FUSION_SIGNING_SECRET, * expectedDigest: process.env.FUSION_EXPECTED_DIGEST, * failOnMismatch: process.env.NODE_ENV === 'production', * }, * }); * ``` * * @see {@link ZeroTrustConfig} for configuration options */ zeroTrust?: ZeroTrustConfig; /** * Enable contract-aware self-healing for validation errors. * * When configured, Zod validation errors are enriched with * contract change context, helping the LLM self-correct * when the tool's behavioral contract has changed. * * Zero overhead when omitted or when no contract deltas exist. * * @see {@link SelfHealingConfig} for configuration options */ selfHealing?: SelfHealingConfig; /** * FSM gate for temporal anti-hallucination. * * When configured, tools bound to FSM states (via `.bindState()`) * are dynamically filtered from `tools/list` based on the current * workflow state. The LLM physically cannot call tools that don't * exist in its reality. * * On successful tool execution, the FSM transitions automatically * (if a transition event is bound), and `notifications/tools/list_changed` * is emitted so the client re-fetches the tool list. * * Zero overhead when omitted — no FSM code runs. * * @example * ```typescript * const gate = new StateMachineGate({ * id: 'checkout', * initial: 'empty', * states: { * empty: { on: { ADD_ITEM: 'has_items' } }, * has_items: { on: { CHECKOUT: 'payment' } }, * payment: { on: { PAY: 'confirmed' } }, * confirmed: { type: 'final' }, * }, * }); * * registry.attachToServer(server, { * contextFactory: createContext, * fsm: gate, * }); * ``` * * @see {@link StateMachineGate} for the FSM engine */ fsm?: StateMachineGate; /** * External state store for FSM persistence in serverless/edge deployments. * * When MCP runs over Streamable HTTP (Vercel, Cloudflare Workers), * there is no persistent process — FSM state must be externalized. * The `sessionId` comes from the `Mcp-Session-Id` request header. * * Zero overhead when omitted — FSM state lives in-memory. * * @example * ```typescript * registry.attachToServer(server, { * fsm: gate, * fsmStore: { * load: async (sessionId) => { * const data = await redis.get(`fsm:${sessionId}`); * return data ? JSON.parse(data) : undefined; * }, * save: async (sessionId, snapshot) => { * await redis.set(`fsm:${sessionId}`, JSON.stringify(snapshot), { EX: 3600 }); * }, * }, * }); * ``` */ fsmStore?: FsmStateStore; } /** Function to detach the registry from the server */ export type DetachFn = () => void; /** Delegate interface for the registry operations needed by ServerAttachment */ export interface RegistryDelegate { getAllTools(): McpTool[]; getTools(filter: { tags?: string[]; anyTag?: string[]; exclude?: string[]; }): McpTool[]; routeCall(ctx: TContext, name: string, args: Record, progressSink?: ProgressSink, signal?: AbortSignal): Promise; /** Propagate a debug observer to all registered builders (duck-typed) */ enableDebug?(observer: DebugObserverFn): void; /** Propagate a tracer to all registered builders (duck-typed) */ enableTracing?(tracer: FusionTracer): void; /** Propagate a telemetry sink to all registered builders (duck-typed) */ enableTelemetry?(sink: TelemetrySink): void; /** Get an iterable of all registered builders (for introspection and exposition) */ getBuilders(): Iterable>; } /** * Attach a registry to an MCP Server. * * Resolves the server type, registers tools/list and tools/call handlers, * and returns a detach function to remove the handlers. * * @param server - Server or McpServer instance (duck-typed) * @param registry - Delegate providing tool listing and routing * @param options - Filter and context factory options * @returns A detach function to remove the handlers */ export declare function attachToServer(server: unknown, registry: RegistryDelegate, options?: AttachOptions): Promise; //# sourceMappingURL=ServerAttachment.d.ts.map