From 511c1a11b555a29192283c317debee2410fbd0b4 Mon Sep 17 00:00:00 2001 From: sid293 Date: Tue, 7 Apr 2026 17:18:01 +0530 Subject: [PATCH] fix: ensure transport is closed when connection initialization fails during client connect --- packages/client/src/client/client.ts | 20 +++++++-------- test/integration/test/client/client.test.ts | 27 +++++++++++++++++++++ 2 files changed, 37 insertions(+), 10 deletions(-) diff --git a/packages/client/src/client/client.ts b/packages/client/src/client/client.ts index 21a43bd15..b2c7680a2 100644 --- a/packages/client/src/client/client.ts +++ b/packages/client/src/client/client.ts @@ -490,17 +490,17 @@ export class Client extends Protocol { * ``` */ override async connect(transport: Transport, options?: RequestOptions): Promise { - await super.connect(transport); - // When transport sessionId is already set this means we are trying to reconnect. - // Restore the protocol version negotiated during the original initialize handshake - // so HTTP transports include the required mcp-protocol-version header, but skip re-init. - if (transport.sessionId !== undefined) { - if (this._negotiatedProtocolVersion !== undefined && transport.setProtocolVersion) { - transport.setProtocolVersion(this._negotiatedProtocolVersion); - } - return; - } try { + await super.connect(transport); + // When transport sessionId is already set this means we are trying to reconnect. + // Restore the protocol version negotiated during the original initialize handshake + // so HTTP transports include the required mcp-protocol-version header, but skip re-init. + if (transport.sessionId !== undefined) { + if (this._negotiatedProtocolVersion !== undefined && transport.setProtocolVersion) { + transport.setProtocolVersion(this._negotiatedProtocolVersion); + } + return; + } const result = await this._requestWithSchema( { method: 'initialize', diff --git a/test/integration/test/client/client.test.ts b/test/integration/test/client/client.test.ts index 52d151bdd..9a714f747 100644 --- a/test/integration/test/client/client.test.ts +++ b/test/integration/test/client/client.test.ts @@ -217,6 +217,33 @@ test('should reject unsupported protocol version', async () => { expect(clientTransport.close).toHaveBeenCalled(); }); +/*** + * Test: Connection Initialization Failure Cleanup + */ +test('should close transport and clean up if connection initialization fails', async () => { + const clientTransport: Transport = { + start: vi.fn().mockRejectedValue(new Error('Transport start failed')), + close: vi.fn().mockResolvedValue(undefined), + send: vi.fn().mockResolvedValue(undefined) + }; + + const client = new Client( + { + name: 'test client', + version: '1.0' + }, + { + capabilities: {} + } + ); + + await expect(client.connect(clientTransport)).rejects.toThrow('Transport start failed'); + + // The transport.close() method should be called to clean up resources + // because the client.connect() method caught the error and called this.close() + expect(clientTransport.close).toHaveBeenCalled(); +}); + /*** * Test: Connect New Client to Old Supported Server Version */