import { Server as McpServer } from '@modelcontextprotocol/sdk/server/index.js'; import type { Express, Response } from 'express'; import { Tool } from './tool.js'; import { Resource, ResourceTemplate } from './resource.js'; import { Prompt } from './prompt.js'; import { McpServerConfig, ExecutionContext, ServerStats, ClassConstructor, ServerStartOptions } from './types.js'; import type { McpTransform } from './transforms/index.js'; import { TaskManager, type TaskStore } from './task.js'; import type { SessionContext } from './transports/streamable-http.js'; import { SessionVisibilityStore } from './transforms/visibility/session-store.js'; import { SpilloverStore } from './interceptors/spillover/spillover-store.interface.js'; import type { TransformTelemetry } from './health/health.interface.js'; /** * HTTP Transport interface */ interface HttpTransport { start(): Promise; close(): Promise; /** Provide the factory used to build a configured MCP server per /mcp session. */ setMcpServerFactory?(factory: (sessionContext?: SessionContext) => McpServer): void; /** Delegate /mcp to a modern (2026-07-28) stateless handler. */ setModernHandler?(handler: (req: unknown, res: Response) => void): void; /** Set the protocol revision label used on health/logs. */ setProtocolVersionLabel?(label: string): void; setLegacySseHandler?(handler: (req: unknown, res: Response) => Promise): void; setToolsCallback?(callback: () => Promise): void; setServerConfig?(config: { name: string; version: string; description?: string; }): void; /** StreamableHttpTransport exposes the Express app for extra routes (legacy SDK SSE). */ getApp?(): Express; } /** * Visibility and spillover key. * * The subject is the verified `extra.auth.subject` only. An unsigned bearer * payload must not select a session. No transport session means no key. * * Anonymous and authenticated callers use disjoint prefixes, and both parts are * encoded, so a client-supplied `mcp-session-id` cannot equal another * principal's key. */ export declare function sessionIsolationKey(transportSessionId: string | undefined, verifiedSubject: string | undefined): string | undefined; /** * NitroStackServer - Main server class */ export declare class NitroStackServer { private mcpServer; /** Process-local session for the legacy stdio peer. Not taken from the client. */ private legacyStdioSessionId?; private tools; private sessionVisibilityStore; private pendingListChangedSessions; private notificationScheduled; private resources; private resourceTemplates; private templateResources; private defaultSpilloverStore; private startTime; private prompts; private modules; private config; private logger; private stats; private pendingComponentRegistrations; /** Transport type used by the server */ private _transportType?; /** Transport options configured during application creation */ private _transportOptions?; /** HTTP transport instance (when using http or dual mode) */ private _httpTransport?; /** SDK legacy HTTP+SSE routes (GET /sse + POST /mcp/messages) attached once per Express app */ private _legacySseRoutesAttached; /** Active sessions for @modelcontextprotocol/sdk SSEServerTransport clients */ private legacySdkSseSessions; /** Task manager for MCP Tasks support */ private taskManager; /** Registered OS signal handlers for graceful shutdown (see enableShutdownHooks) */ private _shutdownSignalHandlers; /** Guards stop() so double signals / repeated calls don't re-run teardown */ private _stopping?; /** * Resolved MCP protocol era. `legacy` (default) keeps the current 2025-era * sessionful path unchanged; `modern` / `auto` engage the 2026-07-28 adapter. */ private protocolEra; /** Lazily constructed modern (2026-07-28) adapter (only on modern/auto). */ private modernAdapter?; /** Registered MCP catalog transforms in pipeline order */ private transforms; constructor(config?: McpServerConfig); /** * Modern HTTP must present a session id this process minted before * tools/list or tools/call. Visibility is not applied to a missing header. */ private noteVisibilityBoundary; /** * Build the read-only registry view the modern protocol adapter consumes. * Captures `this` so the adapter never imports NitroStack internals. */ private buildProtocolRegistry; /** * Lazily create the modern (2026-07-28) protocol adapter. `auto` uses the v2 * stateless legacy fallback so a single endpoint serves both eras for * validation; `modern` rejects legacy-classified traffic. */ private getModernAdapter; /** * Bind an HTTP transport's /mcp endpoint to the correct protocol engine: * the modern stateless handler on modern/auto, or the legacy per-session * SDK factory otherwise. */ private configureTransportForProtocol; /** Shared MCP server constructor options (main + per legacy SSE session) */ private static readonly mcpServerOptions; /** * Build a fresh MCP server instance wired with all of this application's * tool/resource/prompt handlers. Used for transports that require their own * server instance (legacy SSE sessions, official Streamable HTTP sessions), * since a single SDK server can only be connected to one transport at a time. */ createConfiguredMcpServer(sessionContext?: SessionContext): McpServer; /** * SDK-compatible legacy HTTP+SSE: GET /sse (SSEServerTransport) and POST /mcp/messages?sessionId=. * Streamable HTTP stays on GET/POST /mcp. */ private startLegacySdkSseSession; private attachLegacySdkSseRoutes; private attachLegacySdkSseIfNeeded; /** * Add a tool to the server */ tool(tool: Tool): this; /** * Register a tool with the server (alias for tool()). */ registerTool(tool: Tool): this; /** * Get a registered tool by name. */ getTool(name: string): Tool | undefined; /** * Get all registered raw tools, keyed by name. */ getTools(): Map; /** * Register a transform into the MCP tool catalog pipeline. */ addTransform(transform: McpTransform): this; /** * Get all registered transforms in the pipeline. */ getTransforms(): McpTransform[]; /** * Returns live telemetry descriptors for all active transforms in pipeline order. */ getTransformTelemetry(): TransformTelemetry[]; /** * Get server uptime in seconds. */ getUptimeSeconds(): number; /** * Runs all registered transforms sequentially on the current tools catalog. */ runToolPipeline(context?: ExecutionContext): Promise; /** * Resolves a tool by traversing the transforms in onion-order. */ resolveTool(name: string, context?: ExecutionContext): Promise; /** * Register a component as an MCP resource */ private registerComponentResource; /** * Add a resource to the server */ resource(resource: Resource): this; /** * Add a prompt to the server */ prompt(prompt: Prompt): this; /** * Add a resource template to the server */ resourceTemplate(template: ResourceTemplate): this; /** * Initializes the built-in spillover resource template. * Called during server initialization. */ private registerSpilloverResourceTemplate; /** * Get the default spillover store used for payload offloading. */ getSpilloverStore(): SpilloverStore; /** * Set the default spillover store used for payload offloading. */ setSpilloverStore(store: SpilloverStore): this; /** * Notify clients that the list of resources has changed */ notifyResourcesListChanged(): void; /** * Notify clients that the list of prompts has changed */ notifyPromptsListChanged(): void; /** * Get the session visibility store */ getSessionVisibilityStore(): SessionVisibilityStore; /** True when a VisibilityTransform is in the pipeline. */ hasSessionVisibility(): boolean; /** * Dispatches notifications/tools/list_changed. * If sessionId is provided, targets the specific session; if omitted, broadcasts globally. * Coalesced via queueMicrotask to avoid duplicate notifications in a single tick. */ notifyToolsListChanged(sessionId?: string): void; private flushListChangedNotifications; private sendSessionNotification; /** * Notify subscribers that a resource has been updated */ notifyResourceUpdated(uri: string): void; /** * Register a module with all its controllers * Automatically extracts and registers all tools, resources, and prompts * * @example * ```typescript * server.module(AuthModule); * server.module(ProductsModule); * ``` */ module(moduleClass: ClassConstructor): this; /** * Get server statistics */ getStats(): ServerStats; /** * Create execution context */ createContext(options?: { metadata?: Record; toolName?: string; extra?: Partial; }, sessionContext?: SessionContext): ExecutionContext; /** * Build an execution context (alias for createContext()). */ createExecutionContext(options?: { metadata?: Record; toolName?: string; extra?: Partial; }, sessionContext?: SessionContext): ExecutionContext; /** * Register MCP protocol handlers on the given server instance (main or per legacy SSE session). */ private setupHandlersOn; /** * Start the server * Automatically determines the transport based on NODE_ENV * * Transport determination: * - MCP_TRANSPORT_TYPE env var takes precedence (for explicit control) * - NODE_ENV=development or unset → stdio mode * - NODE_ENV=production → dual mode (STDIO + HTTP) */ /** * Start the server. * * Transport determination precedence: * 1. Explicit `options.transport` passed to `start({ transport: 'stdio' })` * 2. `MCP_TRANSPORT_TYPE` environment variable * 3. Configured `this._transportType` (from `@McpApp` / `McpApplicationFactory`) * 4. Default: `NODE_ENV=development` or unset → 'stdio', `production` → 'dual' */ start(options?: ServerStartOptions): Promise; /** * Start the server with specified transport * @param transportType - 'stdio', 'http', or 'dual' (default: 'stdio') * @param transportOptions - Transport-specific options */ private startWithTransport; /** * Execute a tool asynchronously as a task. * Called from the tools/call handler when task-augmented. * Updates task status and stores the result for tasks/result. */ private runTaskAsync; /** * Register a custom JSON-RPC handler for task-related methods. * The MCP SDK's setRequestHandler only works with pre-defined schemas, * so we hook into the transport-level message handling. */ private registerCustomHandler; /** Custom JSON-RPC handlers (for task methods not covered by MCP SDK schemas) */ private _customHandlers; /** * Send a notifications/tasks/status notification to the client. */ private sendTaskStatusNotification; /** * Get the TaskManager instance (useful for advanced use cases) */ getTaskManager(): TaskManager; /** * Configure a custom TaskStore (e.g., Redis, SQL, DynamoDB) for distributed task state */ setTaskStore(store: TaskStore): this; /** * Register OS signal handlers so the server shuts down gracefully, running the * NestJS-style shutdown lifecycle hooks (beforeApplicationShutdown / * onApplicationShutdown) with the received signal. * * Opt-in (like NestJS `enableShutdownHooks`) to avoid attaching process * listeners for consumers that manage their own shutdown. Safe to call more * than once; handlers are only attached once per signal. * * @param signals - Signals to listen for (default: SIGTERM, SIGINT) */ enableShutdownHooks(signals?: NodeJS.Signals[]): this; /** * Remove any process signal handlers registered via enableShutdownHooks(). */ private removeShutdownHooks; /** * Stop the server * * Idempotent: concurrent or repeated calls (e.g. from multiple OS signals) * share the same in-flight teardown instead of re-running lifecycle hooks or * double-closing transports. */ stop(signal?: string): Promise; private doStop; /** * Get the HTTP transport (for modules that need to register endpoints) */ getHttpTransport(): HttpTransport | undefined; } /** * Helper function to create a server */ export declare function createServer(config: McpServerConfig): NitroStackServer; export {}; //# sourceMappingURL=server.d.ts.map