import { Client } from "@modelcontextprotocol/sdk/client"; import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js"; import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js"; import type { McpServerConfig } from "./httpClient"; const pool = new Map(); function keyOf(server: McpServerConfig) { const headers = Object.entries(server.headers ?? {}) .sort(([a], [b]) => a.localeCompare(b)) .map(([k, v]) => `${k}:${v}`) .join("|\u0000|"); return `${server.url}|${headers}`; } export async function getClient(server: McpServerConfig, signal?: AbortSignal): Promise { const key = keyOf(server); const existing = pool.get(key); if (existing) return existing; const client = new Client({ name: "chat-ui-mcp", version: "0.1.0" }); const url = new URL(server.url); const requestInit: RequestInit = { headers: server.headers, signal }; try { try { await client.connect(new StreamableHTTPClientTransport(url, { requestInit })); } catch { await client.connect(new SSEClientTransport(url, { requestInit })); } } catch (err) { try { await client.close?.(); } catch {} throw err; } pool.set(key, client); return client; } export async function drainPool() { for (const [key, client] of pool) { try { await client.close?.(); } catch {} pool.delete(key); } }