{"version":3,"file":"stdio.mjs","names":["_stdin: Readable","_stdout: Writable","_wire: Transport","_onInstanceClose: () => void","_outboundIntercept?: (message: JSONRPCMessage) => 'handled' | undefined","state: EntryState","discarding: StdioConnectionChannel | undefined","channel: StdioConnectionChannel","queue: JSONRPCMessage[]"],"sources":["../src/server/stdio.ts","../src/server/serveStdio.ts"],"sourcesContent":["import type { Readable, Writable } from 'node:stream';\n\nimport type { JSONRPCMessage, Transport } from '@modelcontextprotocol/core-internal';\nimport { ReadBuffer, serializeMessage } from '@modelcontextprotocol/core-internal';\nimport { process } from '@modelcontextprotocol/server/_shims';\n\n/**\n * Marks a stdout `'error'` listener that a closed transport left attached purely to\n * swallow late write failures (see {@link StdioServerTransport.close}). A fresh\n * transport taking over the same stream removes listeners carrying this tag in\n * `start()`, so repeated create→close cycles on the process-global `process.stdout`\n * don't accumulate listeners.\n */\nconst swallowsErrorsAfterClose = Symbol('swallowsErrorsAfterClose');\n\n/**\n * Server transport for stdio: this communicates with an MCP client by reading from the current process' `stdin` and writing to `stdout`.\n *\n * This transport is only available in Node.js environments.\n *\n * When the client closes its end of the pipe (stdin reaches end-of-file), the transport\n * closes itself and fires `onclose`, per the MCP stdio binding's guidance that servers\n * should exit promptly when their standard input is closed. A server that holds no other\n * keep-alive handles will then exit naturally. Requests still in flight when stdin ends are\n * aborted and not answered; a client that expects responses keeps stdin open until it has\n * read them.\n *\n * @example\n * ```ts source=\"./stdio.examples.ts#StdioServerTransport_basicUsage\"\n * const server = new McpServer({ name: 'my-server', version: '1.0.0' });\n * const transport = new StdioServerTransport();\n * await server.connect(transport);\n * ```\n */\nexport class StdioServerTransport implements Transport {\n    private _readBuffer: ReadBuffer;\n    private _started = false;\n    private _closed = false;\n\n    constructor(\n        private _stdin: Readable = process.stdin,\n        private _stdout: Writable = process.stdout,\n        options?: {\n            /**\n             * Maximum size of the read buffer in bytes. If a single message exceeds\n             * this size the transport will emit an error and close.\n             *\n             * Defaults to 10 MB.\n             */\n            maxBufferSize?: number;\n        }\n    ) {\n        this._readBuffer = new ReadBuffer({ maxBufferSize: options?.maxBufferSize });\n    }\n\n    onclose?: () => void;\n    onerror?: (error: Error) => void;\n    onmessage?: (message: JSONRPCMessage) => void;\n\n    // Arrow functions to bind `this` properly, while maintaining function identity.\n    _ondata = (chunk: Buffer) => {\n        try {\n            this._readBuffer.append(chunk);\n            this.processReadBuffer();\n        } catch (error) {\n            this.onerror?.(error as Error);\n            this.close().catch(() => {});\n        }\n    };\n    _onerror = (error: Error) => {\n        this.onerror?.(error);\n    };\n    _onstdouterror = (error: Error) => {\n        if (this._closed) {\n            // Swallow stdout errors that surface after close. A write accepted before\n            // close (`write()` returned true) can still fail asynchronously at the OS\n            // level — e.g. EPIPE when the client that hung up also stops reading our\n            // stdout. The transport is already closed, so there is nothing to do; but\n            // with no listener attached, that late 'error' event would crash the\n            // process with an uncaught exception — which is why close() leaves this\n            // listener attached.\n            return;\n        }\n        this.onerror?.(error);\n        this.close().catch(() => {\n            // Ignore errors during close — we're already in an error path\n        });\n    };\n    _onstdinclose = () => {\n        // stdin reaching EOF (or being destroyed) means the client has hung up and no\n        // further input can ever arrive. The MCP stdio binding says servers should exit\n        // promptly when their standard input closes — this is the primary graceful\n        // shutdown signal, and on some platforms (e.g. Windows) the only reliable one.\n        // Close the transport so `onclose` fires and the process can exit naturally.\n        this.close().catch(() => {\n            // Ignore errors during close — nothing more can be read anyway\n        });\n    };\n\n    /**\n     * Starts listening for messages on `stdin`.\n     */\n    async start(): Promise<void> {\n        if (this._started) {\n            throw new Error(\n                'StdioServerTransport already started! If using Server class, note that connect() calls start() automatically.'\n            );\n        }\n\n        this._started = true;\n        // Remove swallow-only 'error' listeners left behind by previously closed\n        // transports on this stream (see close()). Our own listener covers the\n        // stream from here on, so the stale ones are no longer needed — without\n        // this sweep, repeated create→close cycles on the process-global\n        // process.stdout would accumulate listeners.\n        for (const listener of this._stdout.listeners('error')) {\n            if ((listener as { [swallowsErrorsAfterClose]?: boolean })[swallowsErrorsAfterClose]) {\n                this._stdout.off('error', listener as (error: Error) => void);\n            }\n        }\n        // A stream that already ended or was destroyed before start() ran has\n        // emitted its one 'end'/'close' event; the listeners below would never\n        // fire. This can happen with a custom stream (e.g. a net.Socket the\n        // peer reset during async setup) — treat it as the client having hung\n        // up. Deferred to the next event-loop turn (not a microtask) so it lands\n        // after the caller's start()/connect() continuation, exactly like a real\n        // 'end' would — an onclose assigned right after `await connect()` must\n        // still see it.\n        if (this._stdin.readableEnded || this._stdin.destroyed) {\n            setImmediate(this._onstdinclose);\n        }\n        this._stdin.on('data', this._ondata);\n        this._stdin.on('error', this._onerror);\n        this._stdin.on('end', this._onstdinclose);\n        this._stdin.on('close', this._onstdinclose);\n        this._stdout.on('error', this._onstdouterror);\n    }\n\n    private processReadBuffer() {\n        while (true) {\n            try {\n                const message = this._readBuffer.readMessage();\n                if (message === null) {\n                    break;\n                }\n\n                this.onmessage?.(message);\n            } catch (error) {\n                this.onerror?.(error as Error);\n            }\n        }\n    }\n\n    async close(): Promise<void> {\n        if (this._closed) {\n            return;\n        }\n        this._closed = true;\n\n        // Remove our event listeners first\n        this._stdin.off('data', this._ondata);\n        this._stdin.off('error', this._onerror);\n        this._stdin.off('end', this._onstdinclose);\n        this._stdin.off('close', this._onstdinclose);\n        // Deliberately keep _onstdouterror attached (it is a no-op now that _closed\n        // is set): a write that was accepted before close may still be pending at\n        // the OS level and can fail after close (e.g. EPIPE when the client hangs\n        // up), and an 'error' event on a listener-less stream would crash the\n        // process. Tag it so the next transport to start on this stream can sweep\n        // it away instead of letting closed transports' listeners accumulate.\n        (this._onstdouterror as { [swallowsErrorsAfterClose]?: boolean })[swallowsErrorsAfterClose] = true;\n\n        // Check if we were the only data listener\n        const remainingDataListeners = this._stdin.listenerCount('data');\n        if (remainingDataListeners === 0) {\n            // Only pause stdin if we were the only listener\n            // This prevents interfering with other parts of the application that might be using stdin\n            this._stdin.pause();\n        }\n\n        // Clear the buffer and notify closure\n        this._readBuffer.clear();\n        this.onclose?.();\n    }\n\n    send(message: JSONRPCMessage): Promise<void> {\n        if (this._closed) {\n            return Promise.reject(new Error('StdioServerTransport is closed'));\n        }\n        return new Promise((resolve, reject) => {\n            const json = serializeMessage(message);\n\n            let settled = false;\n            const onError = (error: Error) => {\n                if (settled) return;\n                settled = true;\n                this._stdout.off('error', onError);\n                this._stdout.off('drain', onDrain);\n                reject(error);\n            };\n            const onDrain = () => {\n                if (settled) return;\n                settled = true;\n                this._stdout.off('error', onError);\n                this._stdout.off('drain', onDrain);\n                resolve();\n            };\n\n            this._stdout.once('error', onError);\n\n            if (this._stdout.write(json)) {\n                if (settled) return;\n                settled = true;\n                this._stdout.off('error', onError);\n                resolve();\n            } else if (!settled) {\n                this._stdout.once('drain', onDrain);\n            }\n        });\n    }\n}\n","/**\n * `serveStdio` — the stdio entry point for serving the 2026-07-28 protocol\n * revision on a long-lived connection, with 2025-era serving as the default\n * for clients that open with the `initialize` handshake.\n *\n * The entry owns the stdio transport and the era decision for the connection.\n * It classifies the connection's opening exchange exactly once (using the\n * same body-primary rules as the HTTP entry), constructs ONE server instance\n * from the consumer's factory for the era the client opened with, pins that\n * instance for the lifetime of the connection, and passes every later message\n * straight through to it. No per-message era classification ever runs after\n * the connection is pinned — exactly mirroring how `createMcpHandler`\n * classifies an HTTP request before any instance exists.\n *\n * The opening exchange:\n *\n * - An `initialize` request (or any claim-less message) opens a 2025-era\n *   session: the factory builds a legacy instance and the connection is\n *   pinned to it (`legacy: 'serve'`, the default). With `legacy: 'reject'`\n *   the opening is answered with the unsupported-protocol-version error\n *   naming the supported modern revisions instead.\n * - A request carrying a valid per-request `_meta` envelope naming a\n *   supported modern revision pins the connection to a modern instance\n *   (era-marked and given the modern-only handlers, exactly like the HTTP\n *   entry's modern path).\n * - A `server/discover` probe is answered by an optimistically built modern\n *   instance but does NOT pin the connection yet: the spec's stdio\n *   backward-compatibility flow lets a client probe first and then either\n *   continue with modern requests (which pins the connection modern) or fall\n *   back to the `initialize` handshake when no mutually supported modern\n *   revision exists — in which case the probe instance is discarded and a\n *   fresh legacy instance serves the handshake.\n * - Once the modern era is pinned, a later claim-less `initialize` is\n *   rejected with the unsupported-protocol-version error naming the supported\n *   revisions (the spec recommends naming them in any error returned to\n *   `initialize`, and forbids falling back once the modern era is confirmed).\n *\n * Every instance the factory produces serves exactly one era; the ambiguity\n * of the opening exchange lives entirely in this entry. In the probe-fallback\n * case the factory is called twice (once for the discarded probe instance,\n * once for the legacy instance), so factories should be cheap and\n * side-effect-free to construct — the same expectation `createMcpHandler`\n * already sets for per-request construction.\n *\n * Hand-constructed servers connected directly to a `StdioServerTransport`\n * are unaffected by this entry: they keep serving the 2025-era protocol they\n * were written for.\n */\nimport type {\n    CancelledNotificationParams,\n    JSONRPCMessage,\n    JSONRPCNotification,\n    JSONRPCRequest,\n    MessageClassification,\n    MessageExtraInfo,\n    RequestId,\n    Transport,\n    TransportSendOptions\n} from '@modelcontextprotocol/core-internal';\nimport {\n    carriesValidModernEnvelopeClaim,\n    envelopeClaimVersion,\n    hasEnvelopeClaim,\n    isJSONRPCErrorResponse,\n    isJSONRPCNotification,\n    isJSONRPCRequest,\n    isJSONRPCResultResponse,\n    modernOnlyStrictRejection,\n    ProtocolErrorCode,\n    requestMetaOf,\n    setNegotiatedProtocolVersion,\n    SUPPORTED_MODERN_PROTOCOL_VERSIONS,\n    UnsupportedProtocolVersionError,\n    validateEnvelopeMeta\n} from '@modelcontextprotocol/core-internal';\n\nimport type { McpServerFactory } from './createMcpHandler';\nimport { DEFAULT_MAX_SUBSCRIPTIONS, StdioListenRouter } from './listenRouter';\nimport { McpServer } from './mcp';\nimport type { Server } from './server';\nimport { installModernOnlyHandlers, serverIdentityOf } from './server';\nimport { StdioServerTransport } from './stdio';\n\n/** Options for {@linkcode serveStdio}. */\nexport interface ServeStdioOptions {\n    /**\n     * How a 2025-era opening (an `initialize` request, or any claim-less\n     * message) is handled:\n     *\n     * - `'serve'` (default) — the connection is pinned to a 2025-era instance\n     *   from the same factory and served exactly as a hand-wired stdio server\n     *   serves it today.\n     * - `'reject'` — the opening request is answered with the\n     *   unsupported-protocol-version error naming the supported modern\n     *   revisions (claim-less notifications are dropped); the connection\n     *   stays open for a modern opening.\n     */\n    legacy?: 'serve' | 'reject';\n    /**\n     * Bring your own transport (for example a `StdioServerTransport`\n     * constructed over a Unix domain socket or TCP stream, per the stdio\n     * binding's custom-transport guidance). Defaults to a\n     * {@linkcode StdioServerTransport} over the current process's stdio. The\n     * entry owns the transport: it starts it, receives every inbound message,\n     * and closes it when the connection ends.\n     */\n    transport?: Transport;\n    /** Callback for out-of-band errors (reporting only; it never alters what is written to the wire). */\n    onerror?: (error: Error) => void;\n    /**\n     * Reject a new `subscriptions/listen` with `-32603` 'Subscription limit\n     * reached' (in-band, before the ack) when this many subscriptions are\n     * already open on this connection.\n     * @default 1024\n     */\n    maxSubscriptions?: number;\n}\n\n/** The handle returned by {@linkcode serveStdio}. */\nexport interface StdioServerHandle {\n    /** Tears the connection down: closes the pinned instance (if any) and the underlying transport. */\n    close(): Promise<void>;\n}\n\n/* ------------------------------------------------------------------------ *\n * Per-instance channel\n * ------------------------------------------------------------------------ */\n\n/**\n * How long the probe-discard path waits for the probe instance to answer the\n * requests it was delivered before closing it. The wait normally settles as\n * soon as the DiscoverResult is handed to the wire (or immediately, when a\n * delivered cancellation already settled the probe); the bound is a backstop\n * so no edge can ever hold the connection's inbound pump indefinitely behind\n * the discard.\n */\nconst DISCARD_ANSWER_TIMEOUT_MS = 3000;\n\n/**\n * The transport a pinned instance is connected to: a thin channel that writes\n * through to the entry-owned wire transport and receives the messages the\n * entry forwards. The wire transport itself is never handed to an instance —\n * that is what lets the entry discard an optimistic probe instance (close the\n * channel) without tearing down the connection.\n */\nclass StdioConnectionChannel implements Transport {\n    onclose?: () => void;\n    onerror?: (error: Error) => void;\n    onmessage?: <T extends JSONRPCMessage>(message: T, extra?: MessageExtraInfo) => void;\n\n    private _closed = false;\n    /** Request ids the entry delivered to the instance that the instance has not yet answered. */\n    private readonly _pendingRequests = new Set<RequestId>();\n    private _drainWaiters: Array<() => void> = [];\n\n    constructor(\n        private readonly _wire: Transport,\n        private readonly _onInstanceClose: () => void,\n        /**\n         * Optional first-look on outbound messages. When set and returning\n         * `'handled'`, the channel does not write the message to the wire\n         * (the entry already wrote whatever was appropriate). Used by the\n         * modern-era listen router to fan a change notification out onto the\n         * active subscriptions instead of broadcasting it unsolicited.\n         */\n        private readonly _outboundIntercept?: (message: JSONRPCMessage) => 'handled' | undefined\n    ) {}\n\n    async start(): Promise<void> {\n        // The entry already started the wire transport; connecting an\n        // instance to its channel must not start anything again.\n    }\n\n    async send(message: JSONRPCMessage, options?: TransportSendOptions): Promise<void> {\n        if (isJSONRPCResultResponse(message) || isJSONRPCErrorResponse(message)) {\n            // The instance answered a delivered request: settle it whether or\n            // not the wire write below succeeds (write failures surface\n            // through the wire's own error reporting).\n            const { id } = message;\n            if (id !== undefined) {\n                this._settle(id);\n            }\n        }\n        if (this._closed) {\n            // A discarded or torn-down instance has nowhere to write; late\n            // sends are dropped.\n            return;\n        }\n        if (this._outboundIntercept?.(message) === 'handled') {\n            return;\n        }\n        return this._wire.send(message, options);\n    }\n\n    setProtocolVersion = (version: string): void => {\n        this._wire.setProtocolVersion?.(version);\n    };\n\n    /** Forwards one inbound message to the connected instance. */\n    deliver(message: JSONRPCMessage, extra?: MessageExtraInfo): void {\n        if (this._closed) {\n            return;\n        }\n        if (isJSONRPCRequest(message)) {\n            this._pendingRequests.add(message.id);\n        } else if (isJSONRPCNotification(message) && message.method === 'notifications/cancelled') {\n            // By protocol contract a cancelled request may legitimately go\n            // unanswered (the instance aborts the in-flight handler and writes\n            // nothing for it), so a delivered cancellation settles the request\n            // it names: nothing should keep waiting for an answer that may\n            // never come. Non-cancelled requests still settle only when their\n            // answer is handed to the wire.\n            const cancelledId = (message.params as CancelledNotificationParams | undefined)?.requestId;\n            if (cancelledId !== undefined) {\n                this._settle(cancelledId);\n            }\n        }\n        this.onmessage?.(message, extra);\n    }\n\n    /**\n     * Resolves once every request delivered to the instance has been answered\n     * through {@linkcode send}, settled by a delivered cancellation, or the\n     * channel has been closed and nothing further can be answered. The wait is\n     * bounded by `timeoutMs` as a backstop so no edge can hold the caller\n     * indefinitely; resolves `false` only when the bound elapsed with requests\n     * still unanswered. Used by the probe-discard path so a probe request the\n     * entry accepted is never silently dropped.\n     */\n    async whenRequestsAnswered(timeoutMs: number): Promise<boolean> {\n        if (this._closed || this._pendingRequests.size === 0) {\n            return true;\n        }\n        return await new Promise<boolean>(resolve => {\n            const waiter = (): void => {\n                clearTimeout(timer);\n                resolve(true);\n            };\n            const timer = setTimeout(() => {\n                this._drainWaiters = this._drainWaiters.filter(pending => pending !== waiter);\n                resolve(false);\n            }, timeoutMs);\n            this._drainWaiters.push(waiter);\n        });\n    }\n\n    async close(): Promise<void> {\n        if (this._closed) {\n            return;\n        }\n        this._closed = true;\n        // Nothing further can be answered through a closed channel; release\n        // anyone waiting on in-flight answers.\n        this._pendingRequests.clear();\n        this._releaseDrainWaiters();\n        try {\n            this._onInstanceClose();\n        } finally {\n            this.onclose?.();\n        }\n    }\n\n    private _settle(id: RequestId): void {\n        this._pendingRequests.delete(id);\n        if (this._pendingRequests.size === 0) {\n            this._releaseDrainWaiters();\n        }\n    }\n\n    private _releaseDrainWaiters(): void {\n        const waiters = this._drainWaiters;\n        this._drainWaiters = [];\n        for (const waiter of waiters) {\n            waiter();\n        }\n    }\n}\n\n/* ------------------------------------------------------------------------ *\n * Opening-exchange classification\n * ------------------------------------------------------------------------ */\n\ninterface EnvelopeIssue {\n    key: string;\n    problem: string;\n}\n\ntype OpeningClassification =\n    /** A 2025-era opening: `initialize`, or any message without an envelope claim. */\n    | { kind: 'legacy'; reason: 'initialize' | 'no-claim'; requestedVersion?: string }\n    /** A valid envelope claim naming a modern revision this entry serves. */\n    | { kind: 'modern'; revision: string; classification: MessageClassification }\n    /** A present envelope claim whose envelope is malformed. */\n    | { kind: 'invalid-envelope'; issue: EnvelopeIssue }\n    /** A valid envelope claim naming a revision this entry does not serve (unknown future or 2025-era). */\n    | { kind: 'unsupported-revision'; requested: string };\n\n/**\n * Classifies one message of the opening exchange with the same body-primary\n * rules the HTTP entry applies per request: `initialize` is the legacy\n * handshake unless it carries a valid modern envelope claim; a present claim\n * is validated (never silently ignored); a claim-less message is 2025-era\n * traffic. There is no header layer on stdio, so the body is the only signal.\n */\nfunction classifyOpeningMessage(message: JSONRPCRequest | JSONRPCNotification): OpeningClassification {\n    const params = message.params;\n\n    if (message.method === 'initialize' && !carriesValidModernEnvelopeClaim(params)) {\n        const requestedVersion =\n            params !== null && typeof params === 'object' && typeof (params as { protocolVersion?: unknown }).protocolVersion === 'string'\n                ? ((params as { protocolVersion: string }).protocolVersion as string)\n                : undefined;\n        return { kind: 'legacy', reason: 'initialize', ...(requestedVersion !== undefined && { requestedVersion }) };\n    }\n\n    if (!hasEnvelopeClaim(params)) {\n        return { kind: 'legacy', reason: 'no-claim' };\n    }\n\n    // A present claim is validated, never silently ignored — a malformed\n    // envelope behind the claim is an invalid-params answer, not a fall back\n    // to legacy serving (mirrors the HTTP entry's envelope rung).\n    const meta = requestMetaOf(params);\n    const issues = meta === undefined ? [] : validateEnvelopeMeta(meta);\n    const firstIssue = issues[0];\n    if (firstIssue !== undefined) {\n        return { kind: 'invalid-envelope', issue: firstIssue };\n    }\n\n    const claimedVersion = envelopeClaimVersion(params);\n    if (claimedVersion === undefined || !SUPPORTED_MODERN_PROTOCOL_VERSIONS.includes(claimedVersion)) {\n        // The claim names a revision this entry does not serve (an unknown\n        // future revision, or a 2025-era revision delivered via the envelope\n        // mechanism) — answered like the HTTP entry's modern path.\n        return { kind: 'unsupported-revision', requested: claimedVersion ?? 'unknown' };\n    }\n\n    return { kind: 'modern', revision: claimedVersion, classification: { era: 'modern', revision: claimedVersion } };\n}\n\n/* ------------------------------------------------------------------------ *\n * The entry\n * ------------------------------------------------------------------------ */\n\ninterface ConnectedInstance {\n    product: McpServer | Server;\n    channel: StdioConnectionChannel;\n}\n\ntype EntryState =\n    /** Waiting for the connection's opening message. */\n    | { phase: 'opening' }\n    /** A `server/discover` probe was answered; the era is not pinned yet. */\n    | { phase: 'probe'; instance: ConnectedInstance }\n    /** The connection is pinned to one instance serving one era. */\n    | { phase: 'pinned'; era: 'legacy' | 'modern'; instance: ConnectedInstance }\n    | { phase: 'closed' };\n\n/**\n * Serves MCP over stdio from a server factory, owning the era decision for\n * the connection: the opening exchange selects the era, ONE instance from the\n * factory is pinned for the connection lifetime, and everything after passes\n * straight through to it. See the module documentation for the opening rules.\n *\n * ```ts\n * import { serveStdio } from '@modelcontextprotocol/server/stdio';\n *\n * serveStdio(() => {\n *     const server = new McpServer({ name: 'my-server', version: '1.0.0' }, { capabilities: { tools: {} } });\n *     // register tools/resources/prompts once — the same factory serves both eras\n *     return server;\n * });\n * ```\n */\nexport function serveStdio(factory: McpServerFactory, options: ServeStdioOptions = {}): StdioServerHandle {\n    const legacyMode = options.legacy ?? 'serve';\n    const wire = options.transport ?? new StdioServerTransport();\n\n    let state: EntryState = { phase: 'opening' };\n    /** Channel currently being discarded (its close must not tear the connection down). */\n    let discarding: StdioConnectionChannel | undefined;\n    let closing = false;\n\n    /**\n     * Whether the connection has been torn down (`handle.close()` or the wire\n     * closing). The opening arms re-check this after every await: a close can\n     * race factory construction, and the continuation must neither resurrect\n     * the connection state nor keep a late-resolved instance around.\n     */\n    const isTornDown = (): boolean => closing || state.phase === 'closed';\n\n    const reportError = (error: Error) => {\n        try {\n            options.onerror?.(error);\n        } catch {\n            // Reporting must never affect the wire.\n        }\n    };\n\n    const writeErrorResponse = (id: RequestId, code: number, message: string, data?: unknown): Promise<void> =>\n        wire\n            .send({ jsonrpc: '2.0', id, error: { code, message, ...(data !== undefined && { data }) } })\n            .catch(error => reportError(toError(error)));\n\n    /**\n     * Entry-handled `subscriptions/listen` for this connection: holds the\n     * active subscriptions, serves inbound listen / cancelled-of-listen\n     * before the pinned instance is consulted, and rewrites the instance's\n     * outbound change notifications onto the active subscriptions. Only\n     * consulted on a modern-pinned connection — on a legacy connection\n     * change notifications pass straight through (the 2025 unsolicited\n     * delivery model is unchanged).\n     */\n    const listenRouter = new StdioListenRouter(options.maxSubscriptions ?? DEFAULT_MAX_SUBSCRIPTIONS);\n\n    /** Outbound intercept installed on a modern instance's channel. */\n    const modernOutboundIntercept = (message: JSONRPCMessage): 'handled' | undefined => {\n        if (!isJSONRPCNotification(message)) return undefined;\n        const routed = listenRouter.routeOutbound(message);\n        if (routed === 'passthrough') return undefined;\n        // A subscription-gated change notification on the modern era: one\n        // stamped copy per subscription that opted in (an empty array means\n        // it is dropped — the modern era never delivers an un-requested\n        // change type unsolicited). Nothing else from the instance is\n        // affected.\n        for (const stamped of routed) {\n            void wire.send({ jsonrpc: '2.0', ...stamped }).catch(error => reportError(toError(error)));\n        }\n        return 'handled';\n    };\n\n    /**\n     * Entry-handled inbound listen routing for a modern-pinned connection.\n     * Returns `true` when the message was served at the entry and must NOT\n     * be delivered to the pinned instance.\n     */\n    const tryServeListen = async (message: JSONRPCMessage): Promise<boolean> => {\n        if (isJSONRPCRequest(message) && message.method === 'subscriptions/listen') {\n            // Entry-handled listen is its own request-handling subsystem; it\n            // applies the same per-request envelope rung the instance's\n            // `_onrequest` would (method-existence is N/A here — the entry\n            // recognized the method — so envelope validation is the first\n            // applicable rung) and the same supported-revision check the\n            // opening classifier and the HTTP entry apply per request. Reuses\n            // the same validators the opening classifier uses.\n            const meta = requestMetaOf(message.params);\n            const issue = hasEnvelopeClaim(message.params)\n                ? (meta === undefined ? [] : validateEnvelopeMeta(meta))[0]\n                : { key: '_meta', problem: 'the per-request envelope is required on protocol revision 2026-07-28' };\n            const claimedVersion = envelopeClaimVersion(message.params);\n            let reply;\n            if (issue !== undefined) {\n                reply = {\n                    jsonrpc: '2.0' as const,\n                    id: message.id,\n                    error: { code: -32_602, message: `Invalid _meta envelope: ${issue.key}: ${issue.problem}` }\n                };\n            } else if (claimedVersion === undefined || !SUPPORTED_MODERN_PROTOCOL_VERSIONS.includes(claimedVersion)) {\n                const error = new UnsupportedProtocolVersionError({\n                    supported: [...SUPPORTED_MODERN_PROTOCOL_VERSIONS],\n                    requested: claimedVersion ?? 'unknown'\n                });\n                reply = { jsonrpc: '2.0' as const, id: message.id, error: { code: error.code, message: error.message, data: error.data } };\n            } else {\n                reply = listenRouter.serve(message);\n            }\n            await wire\n                .send('error' in reply ? reply : { jsonrpc: '2.0', method: reply.method, params: reply.params })\n                .catch(error => reportError(toError(error)));\n            return true;\n        }\n        if (isJSONRPCNotification(message) && message.method === 'notifications/cancelled') {\n            const cancelledId = (message.params as CancelledNotificationParams | undefined)?.requestId;\n            // Inbound cancel of a parked listen: tear the subscription down\n            // and DO NOT deliver to the instance (it never saw the listen\n            // request). After this point nothing further is delivered for\n            // that subscription id (post-cancel hardening).\n            if (cancelledId !== undefined && listenRouter.cancel(cancelledId)) {\n                return true;\n            }\n        }\n        return false;\n    };\n\n    /** Answers a 2025-era request the entry will not serve (the modern-only rejection cells). */\n    const answerLegacyRejection = (\n        request: JSONRPCRequest,\n        reason: 'initialize' | 'no-claim',\n        requestedVersion?: string\n    ): Promise<void> => {\n        const rejection = modernOnlyStrictRejection(\n            { kind: 'legacy', reason, ...(requestedVersion !== undefined && { requestedVersion }) },\n            SUPPORTED_MODERN_PROTOCOL_VERSIONS\n        );\n        if (rejection === undefined) {\n            return Promise.resolve();\n        }\n        reportError(new Error(`Rejected 2025-era request on a modern-only stdio connection (${rejection.cell}): ${rejection.message}`));\n        return writeErrorResponse(request.id, rejection.code, rejection.message, rejection.data);\n    };\n\n    const onInstanceClosed = (channel: StdioConnectionChannel) => {\n        if (closing || channel === discarding) {\n            return;\n        }\n        // The pinned (or probe) instance was closed from the instance side:\n        // the connection is over.\n        void closeAll();\n    };\n\n    const connectInstance = async (era: 'legacy' | 'modern', revision?: string): Promise<ConnectedInstance> => {\n        const product = await factory({ era });\n        const server = product instanceof McpServer ? product.server : product;\n        if (era === 'modern') {\n            // Era-write at instance binding, then modern-only handler\n            // installation — the same helpers the HTTP entry's modern path\n            // uses, before the instance is connected.\n            setNegotiatedProtocolVersion(server, revision);\n            installModernOnlyHandlers(server, SUPPORTED_MODERN_PROTOCOL_VERSIONS);\n            // The listen router was created before this instance existed; now\n            // that capabilities are known, hand them over (with the identity\n            // stamped onto graceful-close results) so the acknowledged filter\n            // is narrowed against what the server actually advertises.\n            listenRouter.setServerCapabilities(server.getCapabilities(), serverIdentityOf(server));\n        }\n        const channel: StdioConnectionChannel = new StdioConnectionChannel(\n            wire,\n            () => onInstanceClosed(channel),\n            era === 'modern' ? modernOutboundIntercept : undefined\n        );\n        await product.connect(channel);\n        return { product, channel };\n    };\n\n    /** Closes an instance whose factory resolved only after the connection was torn down. */\n    const disposeLateInstance = (instance: ConnectedInstance): Promise<void> =>\n        instance.product.close().catch(error => reportError(toError(error)));\n\n    const discardProbeInstance = async (instance: ConnectedInstance): Promise<void> => {\n        // The probe instance served only the discover exchange; closing its\n        // channel must not tear down the connection the fallback is about to\n        // continue on.\n        discarding = instance.channel;\n        try {\n            // A probe request the entry accepted must never go silently\n            // unanswered: a client may pipeline its fallback `initialize`\n            // straight behind `server/discover` without waiting, and closing\n            // the instance aborts whatever it still has in flight. Let the\n            // in-flight DiscoverResult reach the wire before the instance is\n            // closed; the probe instance only ever receives `server/discover`,\n            // whose entry-installed handler always answers promptly. A probe\n            // the client cancelled is already settled by the delivered\n            // cancellation (a cancelled request may go unanswered), and the\n            // wait is bounded as a backstop so nothing can wedge the\n            // connection's pump behind the discard.\n            const answered = await instance.channel.whenRequestsAnswered(DISCARD_ANSWER_TIMEOUT_MS);\n            if (!answered) {\n                reportError(\n                    new Error(\n                        `Discarded the probe instance with requests still unanswered after ${DISCARD_ANSWER_TIMEOUT_MS}ms; continuing with the fallback`\n                    )\n                );\n            }\n            await instance.product.close();\n        } catch (error) {\n            reportError(toError(error));\n        } finally {\n            discarding = undefined;\n        }\n    };\n\n    const processMessage = async (message: JSONRPCMessage): Promise<void> => {\n        if (state.phase === 'closed') {\n            return;\n        }\n\n        if (state.phase === 'pinned') {\n            if (\n                state.era === 'modern' &&\n                isJSONRPCRequest(message) &&\n                message.method === 'initialize' &&\n                !carriesValidModernEnvelopeClaim(message.params)\n            ) {\n                // The modern era is confirmed for this connection; a late\n                // legacy handshake is answered with the version error naming\n                // the supported revisions (the specification recommends\n                // naming them in any error returned to `initialize`, and\n                // rules out falling back once the modern era is confirmed).\n                const requestedVersion =\n                    message.params !== null &&\n                    typeof message.params === 'object' &&\n                    typeof (message.params as { protocolVersion?: unknown }).protocolVersion === 'string'\n                        ? ((message.params as { protocolVersion: string }).protocolVersion as string)\n                        : undefined;\n                await answerLegacyRejection(message, 'initialize', requestedVersion);\n                return;\n            }\n            if (state.era === 'modern' && (await tryServeListen(message))) {\n                return;\n            }\n            if (isTornDown()) {\n                // Closed while entry listen routing was being checked (a\n                // buffered final message can race stdin EOF): stay closed.\n                return;\n            }\n            state.instance.channel.deliver(message);\n            return;\n        }\n\n        // Negotiation window ('opening' | 'probe').\n        if (!isJSONRPCRequest(message) && !isJSONRPCNotification(message)) {\n            // A JSON-RPC response before any era is pinned: nothing has been\n            // asked of the client yet, so there is nothing it can answer.\n            reportError(new Error('Discarded a JSON-RPC response received before the connection negotiated an era'));\n            return;\n        }\n\n        const opening = classifyOpeningMessage(message);\n        switch (opening.kind) {\n            case 'invalid-envelope': {\n                const detail = `Invalid _meta envelope for protocol revision 2026-07-28: ${opening.issue.key}: ${opening.issue.problem}`;\n                if (isJSONRPCRequest(message)) {\n                    await writeErrorResponse(message.id, ProtocolErrorCode.InvalidParams, detail, { envelope: opening.issue });\n                } else {\n                    reportError(new Error(`Discarded a notification with a malformed envelope: ${detail}`));\n                }\n                return;\n            }\n            case 'unsupported-revision': {\n                if (isJSONRPCRequest(message)) {\n                    const error = new UnsupportedProtocolVersionError({\n                        supported: [...SUPPORTED_MODERN_PROTOCOL_VERSIONS],\n                        requested: opening.requested\n                    });\n                    reportError(error);\n                    await writeErrorResponse(message.id, error.code, error.message, error.data);\n                } else {\n                    reportError(new Error(`Discarded a notification claiming unsupported protocol revision ${opening.requested}`));\n                }\n                return;\n            }\n            case 'modern': {\n                if (isJSONRPCRequest(message) && message.method === 'server/discover') {\n                    if (state.phase === 'probe') {\n                        // A repeated probe is answered by the same optimistic\n                        // instance and the negotiation window stays open: only\n                        // a non-discover enveloped request commits the\n                        // connection to the modern era, so a later fallback\n                        // `initialize` is still served by a fresh legacy\n                        // instance.\n                        state.instance.channel.deliver(message, { classification: opening.classification });\n                        return;\n                    }\n                    // Probe: answer from an optimistically built modern\n                    // instance so the advertisement reflects the real server\n                    // definition, but do not pin the connection yet — the\n                    // client may still fall back to `initialize` when it\n                    // shares no modern revision with the advertisement.\n                    const instance = await connectInstance('modern', opening.revision);\n                    if (isTornDown()) {\n                        // The connection was torn down while the factory was\n                        // building the probe instance: dispose of it and stay\n                        // closed instead of resurrecting the negotiation\n                        // window; nothing is delivered or answered.\n                        await disposeLateInstance(instance);\n                        return;\n                    }\n                    state = { phase: 'probe', instance };\n                    instance.channel.deliver(message, { classification: opening.classification });\n                    return;\n                }\n                if (state.phase === 'probe') {\n                    if (isJSONRPCNotification(message)) {\n                        // An enveloped notification during the negotiation\n                        // window (for example a notifications/cancelled for\n                        // the probe itself) is delivered to the probe instance\n                        // without committing the era: only a non-discover\n                        // enveloped request pins the connection, so a later\n                        // fallback `initialize` is still served by a fresh\n                        // legacy instance.\n                        state.instance.channel.deliver(message, { classification: opening.classification });\n                        return;\n                    }\n                    // The probe was followed by a modern request: the client\n                    // committed to the modern era — pin the probe instance.\n                    state = { phase: 'pinned', era: 'modern', instance: state.instance };\n                } else {\n                    const instance = await connectInstance('modern', opening.revision);\n                    if (isTornDown()) {\n                        // Closed while the factory was building the modern\n                        // instance: dispose of it and stay closed.\n                        await disposeLateInstance(instance);\n                        return;\n                    }\n                    state = { phase: 'pinned', era: 'modern', instance };\n                }\n                if (await tryServeListen(message)) {\n                    return;\n                }\n                if (isTornDown()) {\n                    // Closed while entry listen routing was being checked (a\n                    // buffered final message can race stdin EOF): stay closed.\n                    return;\n                }\n                state.instance.channel.deliver(message, { classification: opening.classification });\n                return;\n            }\n            case 'legacy': {\n                if (legacyMode === 'reject') {\n                    if (isJSONRPCRequest(message)) {\n                        await answerLegacyRejection(message, opening.reason, opening.requestedVersion);\n                    }\n                    // Claim-less notifications are accepted and dropped (the\n                    // stdio analog of the HTTP entry's 202-and-drop); the\n                    // connection stays open for a modern opening.\n                    return;\n                }\n                if (state.phase === 'probe') {\n                    // Probe-then-fallback: the client probed, found no\n                    // mutually supported modern revision, and fell back to\n                    // the 2025 handshake on the same connection. The probe\n                    // instance is discarded; a fresh legacy instance serves\n                    // the handshake.\n                    await discardProbeInstance(state.instance);\n                    if (isTornDown()) {\n                        // Closed while the probe was being discarded: stay closed.\n                        return;\n                    }\n                    state = { phase: 'opening' };\n                }\n                const instance = await connectInstance('legacy');\n                if (isTornDown()) {\n                    // Closed while the factory was building the legacy\n                    // instance: dispose of it and stay closed.\n                    await disposeLateInstance(instance);\n                    return;\n                }\n                state = { phase: 'pinned', era: 'legacy', instance };\n                state.instance.channel.deliver(message);\n                return;\n            }\n        }\n    };\n\n    // Inbound messages are processed strictly in arrival order: the queue\n    // absorbs anything that arrives while the opening exchange is still being\n    // decided (factory construction and instance connection are async).\n    const queue: JSONRPCMessage[] = [];\n    let pumping = false;\n    const pump = async (): Promise<void> => {\n        if (pumping) {\n            return;\n        }\n        pumping = true;\n        try {\n            while (queue.length > 0) {\n                const message = queue.shift()!;\n                try {\n                    await processMessage(message);\n                } catch (error) {\n                    // Every arm of processMessage that answers a request does\n                    // so through writeErrorResponse (which never throws — wire\n                    // failures are routed to onerror) and returns right after,\n                    // so an error escaping to here means the request was never\n                    // answered. Answer it now: a throwing factory or a failed\n                    // connect during the opening exchange must not leave the\n                    // client's request hanging (the stdio analog of the HTTP\n                    // entry's internal-server-error response). Notifications\n                    // carry no id to answer and are only reported.\n                    if (isJSONRPCRequest(message)) {\n                        await writeErrorResponse(message.id, ProtocolErrorCode.InternalError, 'Internal server error');\n                    }\n                    reportError(toError(error));\n                }\n            }\n        } finally {\n            pumping = false;\n        }\n    };\n\n    const closeAll = async (): Promise<void> => {\n        if (closing || state.phase === 'closed') {\n            return;\n        }\n        closing = true;\n        const current = state;\n        state = { phase: 'closed' };\n        // Stdio server-side graceful teardown: emit the empty\n        // `subscriptions/listen` JSON-RPC result for every active subscription\n        // (the spec's graceful-close signal — `SubscriptionsListenResult`)\n        // before the wire is closed, so the client distinguishes graceful end\n        // from a transport drop.\n        for (const result of listenRouter.teardownAll()) {\n            await wire.send(result).catch(error => reportError(toError(error)));\n        }\n        if (current.phase === 'probe' || current.phase === 'pinned') {\n            await current.instance.product.close().catch(error => reportError(toError(error)));\n        }\n        await wire.close().catch(error => reportError(toError(error)));\n    };\n\n    wire.onmessage = (message: JSONRPCMessage) => {\n        queue.push(message);\n        void pump();\n    };\n    wire.onerror = error => {\n        reportError(error);\n        if (state.phase === 'probe' || state.phase === 'pinned') {\n            state.instance.channel.onerror?.(error);\n        }\n    };\n    wire.onclose = () => {\n        if (closing || state.phase === 'closed') {\n            return;\n        }\n        closing = true;\n        const current = state;\n        state = { phase: 'closed' };\n        if (current.phase === 'probe' || current.phase === 'pinned') {\n            void current.instance.product.close().catch(error => reportError(toError(error)));\n        }\n    };\n\n    const started = wire.start().catch(error => {\n        reportError(toError(error));\n        throw error;\n    });\n    // Surface a failed start through onerror (above); close() still resolves.\n    started.catch(() => {});\n\n    return {\n        close: async () => {\n            await started.catch(() => {});\n            await closeAll();\n        }\n    };\n}\n\nfunction toError(value: unknown): Error {\n    return value instanceof Error ? value : new Error(String(value));\n}\n"],"mappings":"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"}