From 70178e669ae3d78d59d3bb9268b6d85b91ea579e Mon Sep 17 00:00:00 2001 From: naman10parikh Date: Mon, 23 Mar 2026 14:45:46 -0700 Subject: [PATCH] fix: support exactOptionalPropertyTypes in Transport interface Adds explicit `| undefined` to all optional callback properties on the Transport interface and all implementing classes. This allows consumers with `exactOptionalPropertyTypes: true` in their tsconfig.json to use the SDK without type errors. Without this fix, class properties initialized as `undefined` are incompatible with the interface under exactOptionalPropertyTypes, since `T | undefined` is not assignable to `T` when the property is present. Fixes #1314 --- packages/client/src/client/sse.ts | 6 +++--- packages/client/src/client/stdio.ts | 6 +++--- packages/client/src/client/streamableHttp.ts | 6 +++--- packages/client/src/client/websocket.ts | 6 +++--- packages/core/src/shared/transport.ts | 12 ++++++------ packages/core/src/util/inMemory.ts | 8 ++++---- packages/core/test/shared/protocol.test.ts | 6 +++--- .../test/shared/protocolTransportHandling.test.ts | 6 +++--- packages/server/src/server/stdio.ts | 6 +++--- packages/server/src/server/streamableHttp.ts | 8 ++++---- 10 files changed, 35 insertions(+), 35 deletions(-) diff --git a/packages/client/src/client/sse.ts b/packages/client/src/client/sse.ts index 133aa0004..109e85fb9 100644 --- a/packages/client/src/client/sse.ts +++ b/packages/client/src/client/sse.ts @@ -76,9 +76,9 @@ export class SSEClientTransport implements Transport { private _fetchWithInit: FetchLike; private _protocolVersion?: string; - onclose?: () => void; - onerror?: (error: Error) => void; - onmessage?: (message: JSONRPCMessage) => void; + onclose?: (() => void) | undefined; + onerror?: ((error: Error) => void) | undefined; + onmessage?: ((message: JSONRPCMessage) => void) | undefined; constructor(url: URL, opts?: SSEClientTransportOptions) { this._url = url; diff --git a/packages/client/src/client/stdio.ts b/packages/client/src/client/stdio.ts index 6c1571f11..c20c7976e 100644 --- a/packages/client/src/client/stdio.ts +++ b/packages/client/src/client/stdio.ts @@ -96,9 +96,9 @@ export class StdioClientTransport implements Transport { private _serverParams: StdioServerParameters; private _stderrStream: PassThrough | null = null; - onclose?: () => void; - onerror?: (error: Error) => void; - onmessage?: (message: JSONRPCMessage) => void; + onclose?: (() => void) | undefined; + onerror?: ((error: Error) => void) | undefined; + onmessage?: ((message: JSONRPCMessage) => void) | undefined; constructor(server: StdioServerParameters) { this._serverParams = server; diff --git a/packages/client/src/client/streamableHttp.ts b/packages/client/src/client/streamableHttp.ts index a39a6c1d7..32fa5fc6e 100644 --- a/packages/client/src/client/streamableHttp.ts +++ b/packages/client/src/client/streamableHttp.ts @@ -149,9 +149,9 @@ export class StreamableHTTPClientTransport implements Transport { private _serverRetryMs?: number; // Server-provided retry delay from SSE retry field private _reconnectionTimeout?: ReturnType; - onclose?: () => void; - onerror?: (error: Error) => void; - onmessage?: (message: JSONRPCMessage) => void; + onclose?: (() => void) | undefined; + onerror?: ((error: Error) => void) | undefined; + onmessage?: ((message: JSONRPCMessage) => void) | undefined; constructor(url: URL, opts?: StreamableHTTPClientTransportOptions) { this._url = url; diff --git a/packages/client/src/client/websocket.ts b/packages/client/src/client/websocket.ts index cb0c34687..2f26ae256 100644 --- a/packages/client/src/client/websocket.ts +++ b/packages/client/src/client/websocket.ts @@ -10,9 +10,9 @@ export class WebSocketClientTransport implements Transport { private _socket?: WebSocket; private _url: URL; - onclose?: () => void; - onerror?: (error: Error) => void; - onmessage?: (message: JSONRPCMessage) => void; + onclose?: (() => void) | undefined; + onerror?: ((error: Error) => void) | undefined; + onmessage?: ((message: JSONRPCMessage) => void) | undefined; constructor(url: URL) { this._url = url; diff --git a/packages/core/src/shared/transport.ts b/packages/core/src/shared/transport.ts index a04e054ba..e079399f0 100644 --- a/packages/core/src/shared/transport.ts +++ b/packages/core/src/shared/transport.ts @@ -98,14 +98,14 @@ export interface Transport { * * This should be invoked when {@linkcode Transport.close | close()} is called as well. */ - onclose?: () => void; + onclose?: (() => void) | undefined; /** * Callback for when an error occurs. * * Note that errors are not necessarily fatal; they are used for reporting any kind of exceptional condition out of band. */ - onerror?: (error: Error) => void; + onerror?: ((error: Error) => void) | undefined; /** * Callback for when a message (request or response) is received over the connection. @@ -114,21 +114,21 @@ export interface Transport { * * The {@linkcode MessageExtraInfo.requestInfo | requestInfo} can be used to get the original request information (headers, etc.) */ - onmessage?: (message: T, extra?: MessageExtraInfo) => void; + onmessage?: ((message: T, extra?: MessageExtraInfo) => void) | undefined; /** * The session ID generated for this connection. */ - sessionId?: string; + sessionId?: string | undefined; /** * Sets the protocol version used for the connection (called when the initialize response is received). */ - setProtocolVersion?: (version: string) => void; + setProtocolVersion?: ((version: string) => void) | undefined; /** * Sets the supported protocol versions for header validation (called during connect). * This allows the server to pass its supported versions to the transport. */ - setSupportedProtocolVersions?: (versions: string[]) => void; + setSupportedProtocolVersions?: ((versions: string[]) => void) | undefined; } diff --git a/packages/core/src/util/inMemory.ts b/packages/core/src/util/inMemory.ts index a02bcafc9..d37cba35a 100644 --- a/packages/core/src/util/inMemory.ts +++ b/packages/core/src/util/inMemory.ts @@ -14,10 +14,10 @@ export class InMemoryTransport implements Transport { private _otherTransport?: InMemoryTransport; private _messageQueue: QueuedMessage[] = []; - onclose?: () => void; - onerror?: (error: Error) => void; - onmessage?: (message: JSONRPCMessage, extra?: { authInfo?: AuthInfo }) => void; - sessionId?: string; + onclose?: (() => void) | undefined; + onerror?: ((error: Error) => void) | undefined; + onmessage?: ((message: JSONRPCMessage, extra?: { authInfo?: AuthInfo }) => void) | undefined; + sessionId?: string | undefined; /** * Creates a pair of linked in-memory transports that can communicate with each other. One should be passed to a {@linkcode @modelcontextprotocol/client!client/client.Client | Client} and one to a {@linkcode @modelcontextprotocol/server!server/server.Server | Server}. diff --git a/packages/core/test/shared/protocol.test.ts b/packages/core/test/shared/protocol.test.ts index 8675c1e03..682db19bb 100644 --- a/packages/core/test/shared/protocol.test.ts +++ b/packages/core/test/shared/protocol.test.ts @@ -54,9 +54,9 @@ interface TestProtocol { // Mock Transport class class MockTransport implements Transport { - onclose?: () => void; - onerror?: (error: Error) => void; - onmessage?: (message: unknown) => void; + onclose?: (() => void) | undefined; + onerror?: ((error: Error) => void) | undefined; + onmessage?: ((message: unknown) => void) | undefined; async start(): Promise {} async close(): Promise { diff --git a/packages/core/test/shared/protocolTransportHandling.test.ts b/packages/core/test/shared/protocolTransportHandling.test.ts index adc7e2234..f88353705 100644 --- a/packages/core/test/shared/protocolTransportHandling.test.ts +++ b/packages/core/test/shared/protocolTransportHandling.test.ts @@ -8,9 +8,9 @@ import type { EmptyResult, JSONRPCMessage, Notification, Request, Result } from // Mock Transport class class MockTransport implements Transport { id: string; - onclose?: () => void; - onerror?: (error: Error) => void; - onmessage?: (message: unknown) => void; + onclose?: (() => void) | undefined; + onerror?: ((error: Error) => void) | undefined; + onmessage?: ((message: unknown) => void) | undefined; sentMessages: JSONRPCMessage[] = []; constructor(id: string) { diff --git a/packages/server/src/server/stdio.ts b/packages/server/src/server/stdio.ts index 562c6861c..964d5d564 100644 --- a/packages/server/src/server/stdio.ts +++ b/packages/server/src/server/stdio.ts @@ -25,9 +25,9 @@ export class StdioServerTransport implements Transport { private _stdout: Writable = process.stdout ) {} - onclose?: () => void; - onerror?: (error: Error) => void; - onmessage?: (message: JSONRPCMessage) => void; + onclose?: (() => void) | undefined; + onerror?: ((error: Error) => void) | undefined; + onmessage?: ((message: JSONRPCMessage) => void) | undefined; // Arrow functions to bind `this` properly, while maintaining function identity. _ondata = (chunk: Buffer) => { diff --git a/packages/server/src/server/streamableHttp.ts b/packages/server/src/server/streamableHttp.ts index 74e689892..65a06896d 100644 --- a/packages/server/src/server/streamableHttp.ts +++ b/packages/server/src/server/streamableHttp.ts @@ -240,10 +240,10 @@ export class WebStandardStreamableHTTPServerTransport implements Transport { private _retryInterval?: number; private _supportedProtocolVersions: string[]; - sessionId?: string; - onclose?: () => void; - onerror?: (error: Error) => void; - onmessage?: (message: JSONRPCMessage, extra?: MessageExtraInfo) => void; + sessionId?: string | undefined; + onclose?: (() => void) | undefined; + onerror?: ((error: Error) => void) | undefined; + onmessage?: ((message: JSONRPCMessage, extra?: MessageExtraInfo) => void) | undefined; constructor(options: WebStandardStreamableHTTPServerTransportOptions = {}) { this.sessionIdGenerator = options.sessionIdGenerator;