import { type ZodType } from '@frontmcp/lazy-zod'; import { McpServer, type RequestId, type StreamableHTTPServerTransport } from '@frontmcp/protocol'; import { type SSEServerTransport } from '#sse-transport'; import { type FrontMcpLogger, type ServerResponse } from '../../common'; import { type ElicitationStore, type ElicitOptions, type ElicitResult, type PendingElicit } from '../../elicitation'; import { type Scope } from '../../scope'; import { type AuthenticatedServerRequest } from '../../server/server.types'; import { type TransportKey, type TransportType } from '../transport.types'; import { type RecreateableSSEServerTransport } from './sse-transport'; import { type RecreateableStreamableHTTPServerTransport } from './streamable-http-transport'; /** * Base transport type that includes all supported transports. * RecreateableStreamableHTTPServerTransport extends StreamableHTTPServerTransport * and RecreateableSSEServerTransport extends SSEServerTransport, * so they're also included in this union. */ export type SupportedTransport = StreamableHTTPServerTransport | SSEServerTransport | RecreateableStreamableHTTPServerTransport | RecreateableSSEServerTransport; export declare abstract class LocalTransportAdapter { #private; protected readonly scope: Scope; protected readonly key: TransportKey; protected readonly onDispose: () => void; protected logger: FrontMcpLogger; protected transport: T; /** * Pending elicitation request. Only one elicit per session is allowed. * New elicit requests will cancel any pending one. */ protected pendingElicit?: PendingElicit; /** * Session payload fields set during MCP initialize. * Stored on the adapter instance so they survive across requests in SSE mode * (where each POST creates a fresh anonymous HTTP session) and are available * in distributed environments without relying on local in-memory caches. */ private initSessionPayload?; /** * Called by the initialize request handler to persist initialization data * on the transport adapter instance. This data is merged into the session * payload on every subsequent request via ensureAuthInfo(). */ setInitSessionPayload(payload: NonNullable['initSessionPayload']>): void; ready: Promise; server: McpServer; constructor(scope: Scope, key: TransportKey, onDispose: () => void, res: ServerResponse); abstract createTransport(sessionId: string, response: ServerResponse): T; abstract initialize(req: AuthenticatedServerRequest, res: ServerResponse): Promise; /** * Send an elicitation request to the client. * * @param relatedRequestId - The request ID that triggered this elicit * @param message - Message to display to the user * @param requestedSchema - Zod schema for the expected response * @param options - Elicit options (mode, ttl, elicitationId) * @returns ElicitResult with status and typed content */ abstract sendElicitRequest(relatedRequestId: RequestId, message: string, requestedSchema: S, options?: ElicitOptions): Promise ? O : unknown>>; abstract handleRequest(req: AuthenticatedServerRequest, res: ServerResponse): Promise; /** * Whether this transport has already been initialized via the MCP initialize handshake. * Override in subclasses that track initialization state. */ get isInitialized(): boolean; /** * Marks this transport as pre-initialized for session recreation. * Override in subclasses that need to set the MCP SDK's _initialized flag. */ markAsInitialized(): void; /** * Resets initialization state to allow re-initialization. * Override in subclasses that support session re-initialization. */ resetForReinitialization(): void; /** * Re-register the MCP server with the notification service. * Called after resetForReinitialization() to restore the server mapping * that was removed by terminateSession → unregisterServer. */ reregisterServer(): void; connectServer(): Promise; get newRequestId(): RequestId; /** * Get the transport type (sse, streamable-http, etc.). * Used for transport-specific behavior detection. */ get type(): TransportType; destroy(reason?: string): Promise; /** * Ping the connected client for this transport. * Returns true on success, false on timeout/error. */ ping(timeoutMs?: number): Promise; protected ensureAuthInfo(req: AuthenticatedServerRequest, transport: LocalTransportAdapter): import("@frontmcp/protocol").AuthInfo; /** * Get the elicitation store for distributed elicitation support. * Uses Redis in distributed mode, in-memory for single-node. */ protected get elicitStore(): ElicitationStore | undefined; /** * Get the elicitation store, throwing if not initialized. * Use in contexts where elicitation is required (sendElicitRequest, cancelPendingElicit). */ protected requireElicitStore(): ElicitationStore; /** * Cancel any pending elicitation request. * Called before sending a new elicit to enforce single-elicit-per-session. * * This cancels both the local pending elicit (for timeout handling) * and publishes cancel to the store (for distributed mode). * * Note: The local promise is resolved immediately for responsiveness, * then distributed state cleanup follows asynchronously. This non-atomic * sequence is intentional - the worst case is publishing a cancel for * an already-processed elicitation, which is harmless. */ protected cancelPendingElicit(): Promise; /** * Handle an incoming elicitation result from the client. * Returns true if the request was an elicit result and was handled. * * Uses ElicitationResultFlow for processing (with hook support). * In distributed mode, this publishes the result via the elicitation store, * which routes it to the correct node that's waiting for it. */ handleIfElicitResult(req: AuthenticatedServerRequest): boolean; /** * Async handler for elicit result - uses ElicitationResultFlow for processing. * Called from handleIfElicitResult without awaiting to avoid blocking the response. */ private handleElicitResultAsync; /** * Type predicate to check if an app configuration represents a remote MCP app. * Remote apps have a 'urlType' property and are not standalone. */ private isRemoteApp; /** * SEP-2640 §Discovery — opt-in `instructions` text listing each * MCP-visible skill's `skill://` URI. Returns an empty string unless * `skillsConfig.sep2640InInstructions` is true. */ private buildSkillInstructionHints; /** * Build capabilities that should be pre-advertised for remote apps. * Remote apps load their tools/resources/prompts asynchronously after connection, * so we need to pre-advertise listChanged capabilities for proper notification support. */ private buildRemoteCapabilities; } //# sourceMappingURL=transport.local.adapter.d.ts.map