Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 10 additions & 10 deletions packages/client/src/client/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -490,17 +490,17 @@ export class Client extends Protocol<ClientContext> {
* ```
*/
override async connect(transport: Transport, options?: RequestOptions): Promise<void> {
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',
Expand Down
2 changes: 1 addition & 1 deletion packages/client/test/client/auth.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3514,7 +3514,7 @@ describe('OAuth Authorization', () => {
headers: {
'user-agent': 'MyApp/1.0'
}
});
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we need this type assertion to make this work, that's a sign the solution isn't quite there yet.

} as unknown as RequestInit);

await discoverOAuthProtectedResourceMetadata('https://resource.example.com', undefined, wrappedFetch);

Expand Down
27 changes: 27 additions & 0 deletions test/integration/test/client/client.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
*/
Expand Down
Loading