diff --git a/package-lock.json b/package-lock.json index dc9b6609c2..209c294367 100644 --- a/package-lock.json +++ b/package-lock.json @@ -30,7 +30,6 @@ "delay": "^6.0.0", "diff": "^5.2.0", "diff-match-patch": "^1.0.5", - "eventsource": "^3.0.5", "fast-deep-equal": "^3.1.3", "fastest-levenshtein": "^1.0.16", "get-folder-size": "^5.0.0", @@ -48,6 +47,7 @@ "pretty-bytes": "^6.1.1", "puppeteer-chromium-resolver": "^23.0.0", "puppeteer-core": "^23.4.0", + "reconnecting-eventsource": "^1.6.4", "serialize-error": "^11.0.3", "simple-git": "^3.27.0", "sound-play": "^1.1.0", @@ -13359,6 +13359,15 @@ "url": "https://paulmillr.com/funding/" } }, + "node_modules/reconnecting-eventsource": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/reconnecting-eventsource/-/reconnecting-eventsource-1.6.4.tgz", + "integrity": "sha512-0L3IS3wxcNFApTPPHkcbY8Aya7XZIpYDzhxa8j6QSufVkUN018XJKfh2ZaThLBGP/iN5UTz2yweMhkqr0PKa7A==", + "license": "MIT", + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/reflect.getprototypeof": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.8.tgz", diff --git a/package.json b/package.json index e0f1f0f38b..1e1b0ab0d8 100644 --- a/package.json +++ b/package.json @@ -333,7 +333,6 @@ "delay": "^6.0.0", "diff": "^5.2.0", "diff-match-patch": "^1.0.5", - "eventsource": "^3.0.5", "fast-deep-equal": "^3.1.3", "fastest-levenshtein": "^1.0.16", "get-folder-size": "^5.0.0", @@ -351,6 +350,7 @@ "pretty-bytes": "^6.1.1", "puppeteer-chromium-resolver": "^23.0.0", "puppeteer-core": "^23.4.0", + "reconnecting-eventsource": "^1.6.4", "serialize-error": "^11.0.3", "simple-git": "^3.27.0", "sound-play": "^1.1.0", diff --git a/src/services/mcp/McpHub.ts b/src/services/mcp/McpHub.ts index 95a2ca9a86..7dc1fb8531 100644 --- a/src/services/mcp/McpHub.ts +++ b/src/services/mcp/McpHub.ts @@ -1,7 +1,7 @@ import { Client } from "@modelcontextprotocol/sdk/client/index.js" import { StdioClientTransport, StdioServerParameters } from "@modelcontextprotocol/sdk/client/stdio.js" import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js" -import { EventSource } from "eventsource" +import ReconnectingEventSource from "reconnecting-eventsource" import { CallToolResultSchema, ListResourcesResultSchema, @@ -243,8 +243,16 @@ export class McpHub { headers: config.headers, }, } - global.EventSource = EventSource - transport = new SSEClientTransport(new URL(config.url), sseOptions) + // Configure ReconnectingEventSource options + const reconnectingEventSourceOptions = { + max_retry_time: 5000, // Maximum retry time in milliseconds + withCredentials: config.headers?.["Authorization"] ? true : false, // Enable credentials if Authorization header exists + } + global.EventSource = ReconnectingEventSource + transport = new SSEClientTransport(new URL(config.url), { + ...sseOptions, + eventSourceInit: reconnectingEventSourceOptions, + }) // Set up SSE specific error handling transport.onerror = async (error) => { @@ -255,11 +263,6 @@ export class McpHub { this.appendErrorMessage(connection, error.message) } await this.notifyWebviewOfServerChanges() - - // Attempt reconnection for SSE - if (!this.isDisposed) { - await this.handleSSEReconnection(name, config) - } } } @@ -295,26 +298,6 @@ export class McpHub { } } - private async handleSSEReconnection(name: string, config: z.infer): Promise { - const maxRetries = 3 - let retryCount = 0 - - while (retryCount < maxRetries) { - try { - await delay(Math.pow(2, retryCount) * 1000) // Exponential backoff - await this.connectToServer(name, config) - return - } catch (error) { - retryCount++ - console.error(`Retry ${retryCount} failed for ${name}:`, error) - } - } - - vscode.window.showErrorMessage( - `Failed to reconnect to ${name} after ${maxRetries} attempts. Please check your connection.`, - ) - } - private appendErrorMessage(connection: McpConnection, error: string) { const newError = connection.server.error ? `${connection.server.error}\n${error}` : error connection.server.error = newError //.slice(0, 800)