UNPKG

@langchain/mcp-adapters

Version:
1 lines 24.7 kB
{"version":3,"file":"connection.cjs","names":["getDebugLog","hooks: ConnectionManagerConfig","#hooks","#createStreamableHTTPTransport","#createSSETransport","#createStdioTransport","MCPClient","packageJson","LoggingMessageNotificationSchema","InitializedNotificationSchema","CancelledNotificationSchema","PromptListChangedNotificationSchema","ResourceListChangedNotificationSchema","ResourceUpdatedNotificationSchema","RootsListChangedNotificationSchema","ToolListChangedNotificationSchema","key: ClientKeyObject","headers: Record<string, string>","#forkClient","#connections","options: TransportOptions | string","#queryConnection","options: TransportOptions","key","options?: TransportOptions","opts: Client | TransportOptions","connection","serverName: string","args: ResolvedStreamableHTTPConnection","options: StreamableHTTPClientTransportOptions","reconnectionOptions: StreamableHTTPReconnectionOptions","StreamableHTTPClientTransport","options: SSEClientTransportOptions","url","SSEClientTransport","options: ResolvedStdioConnection","StdioClientTransport","headers?: Record<string, string>"],"sources":["../src/connection.ts"],"sourcesContent":["import {\n SSEClientTransport,\n SSEClientTransportOptions,\n} from \"@modelcontextprotocol/sdk/client/sse.js\";\n\nimport { StreamableHTTPClientTransport } from \"@modelcontextprotocol/sdk/client/streamableHttp.js\";\nimport type { OAuthClientProvider } from \"@modelcontextprotocol/sdk/client/auth.js\";\nimport type {\n StreamableHTTPClientTransportOptions,\n StreamableHTTPReconnectionOptions,\n} from \"@modelcontextprotocol/sdk/client/streamableHttp.js\";\nimport { Client as MCPClient } from \"@modelcontextprotocol/sdk/client/index.js\";\nimport { StdioClientTransport } from \"@modelcontextprotocol/sdk/client/stdio.js\";\nimport {\n LoggingMessageNotificationSchema,\n CancelledNotificationSchema,\n InitializedNotificationSchema,\n PromptListChangedNotificationSchema,\n ResourceListChangedNotificationSchema,\n ResourceUpdatedNotificationSchema,\n RootsListChangedNotificationSchema,\n ToolListChangedNotificationSchema,\n} from \"@modelcontextprotocol/sdk/types.js\";\n\nimport { getDebugLog } from \"./logging.js\";\nimport type {\n ResolvedStreamableHTTPConnection,\n ResolvedStdioConnection,\n ResolvedClientConfig,\n} from \"./types.js\";\n\n/**\n * TSDown automatically creates a JS file that allows us to consume the package.json file\n * within ESM and CJS modules.\n */\nimport packageJson from \"../package.json\" with { type: \"json\" };\n\nconst debugLog = getDebugLog(\"connection\");\n\nexport interface Client extends MCPClient {\n /**\n * Fork the client with a new set of headers, it either returns a new client or the same client if the headers are the same\n * @param headers - The headers to fork the client with\n * @returns The forked client\n */\n fork: (headers: Record<string, string>) => Promise<Client>;\n}\n\nexport interface TransportOptions {\n serverName: string;\n headers?: Record<string, string>;\n authProvider?: OAuthClientProvider;\n}\n\ntype ClientKeyObject = Omit<TransportOptions, \"headers\"> & {\n headers?: string;\n};\n\nexport interface Connection {\n transport:\n | StreamableHTTPClientTransport\n | SSEClientTransport\n | StdioClientTransport;\n client: Client;\n transportOptions: ResolvedStdioConnection | ResolvedStreamableHTTPConnection;\n closeCallback: () => Promise<void>;\n}\n\nconst transportTypes = [\"http\", \"sse\", \"stdio\"] as const;\n\ntype ConnectionManagerConfig = Pick<\n ResolvedClientConfig,\n | \"onCancelled\"\n | \"onInitialized\"\n | \"onMessage\"\n | \"onPromptsListChanged\"\n | \"onResourcesListChanged\"\n | \"onResourcesUpdated\"\n | \"onRootsListChanged\"\n | \"onToolsListChanged\"\n>;\n\n/**\n * Manages a pool of MCP clients with different transport, server name and connection configurations.\n * This ensures we don't create multiple connections for the same server with the same configuration.\n */\nexport class ConnectionManager {\n #connections: Map<ClientKeyObject, Connection> = new Map();\n #hooks: ConnectionManagerConfig;\n\n constructor(hooks: ConnectionManagerConfig = {}) {\n this.#hooks = hooks;\n }\n\n async createClient(\n type: \"stdio\",\n serverName: string,\n options: ResolvedStdioConnection\n ): Promise<Client>;\n async createClient(\n type: \"http\",\n serverName: string,\n options: ResolvedStreamableHTTPConnection\n ): Promise<Client>;\n async createClient(\n type: \"sse\",\n serverName: string,\n options: ResolvedStreamableHTTPConnection\n ): Promise<Client>;\n async createClient(\n ...args:\n | [\"stdio\", string, ResolvedStdioConnection]\n | [\"sse\", string, ResolvedStreamableHTTPConnection]\n | [\"http\", string, ResolvedStreamableHTTPConnection]\n ): Promise<Client> {\n const [type, serverName, options] = args;\n if (!transportTypes.includes(type)) {\n throw new Error(`Invalid transport type: ${type}`);\n }\n\n const transport =\n type === \"http\"\n ? await this.#createStreamableHTTPTransport(serverName, options)\n : type === \"sse\"\n ? await this.#createSSETransport(serverName, options)\n : await this.#createStdioTransport(options);\n const mcpClient = new MCPClient({\n name: packageJson.name,\n version: packageJson.version,\n });\n await mcpClient.connect(transport);\n\n if (this.#hooks.onMessage) {\n mcpClient.setNotificationHandler(\n LoggingMessageNotificationSchema,\n (notification) =>\n this.#hooks.onMessage?.(notification.params, {\n server: serverName,\n options,\n })\n );\n }\n\n if (this.#hooks.onInitialized) {\n mcpClient.setNotificationHandler(InitializedNotificationSchema, () =>\n this.#hooks.onInitialized?.({\n server: serverName,\n options,\n })\n );\n }\n\n if (this.#hooks.onCancelled) {\n mcpClient.setNotificationHandler(\n CancelledNotificationSchema,\n (notification) => {\n const { requestId, reason } = notification.params;\n\n if (requestId == null) {\n return;\n }\n\n const result = this.#hooks.onCancelled?.(\n { requestId, reason },\n {\n server: serverName,\n options,\n }\n );\n\n if (result && typeof result.catch === \"function\") {\n result.catch(() => {\n /* ignore hook errors */\n });\n }\n }\n );\n }\n\n if (this.#hooks.onPromptsListChanged) {\n mcpClient.setNotificationHandler(\n PromptListChangedNotificationSchema,\n () =>\n this.#hooks.onPromptsListChanged?.({\n server: serverName,\n options,\n })\n );\n }\n\n if (this.#hooks.onResourcesListChanged) {\n mcpClient.setNotificationHandler(\n ResourceListChangedNotificationSchema,\n () =>\n this.#hooks.onResourcesListChanged?.({\n server: serverName,\n options,\n })\n );\n }\n\n if (this.#hooks.onResourcesUpdated) {\n mcpClient.setNotificationHandler(\n ResourceUpdatedNotificationSchema,\n (notification) =>\n this.#hooks.onResourcesUpdated?.(notification.params, {\n server: serverName,\n options,\n })\n );\n }\n\n if (this.#hooks.onRootsListChanged) {\n mcpClient.setNotificationHandler(RootsListChangedNotificationSchema, () =>\n this.#hooks.onRootsListChanged?.({\n server: serverName,\n options,\n })\n );\n }\n\n if (this.#hooks.onToolsListChanged) {\n mcpClient.setNotificationHandler(ToolListChangedNotificationSchema, () =>\n this.#hooks.onToolsListChanged?.({\n server: serverName,\n options,\n })\n );\n }\n\n const key: ClientKeyObject =\n type === \"stdio\"\n ? { serverName }\n : {\n serverName,\n headers: serializeHeaders(options.headers),\n authProvider: options.authProvider,\n };\n\n const forkClient = (headers: Record<string, string>): Promise<Client> => {\n return this.#forkClient(key, headers);\n };\n\n const client = new Proxy(mcpClient, {\n get(target, prop) {\n if (prop === \"fork\") {\n return forkClient.bind(this);\n }\n\n return target[prop as keyof MCPClient];\n },\n }) as Client;\n\n this.#connections.set(key, {\n transport,\n client,\n transportOptions: options,\n closeCallback: async () => client.close(),\n });\n\n return client;\n }\n\n /**\n * Allows to fork a client with a new set of headers\n */\n #forkClient(\n key: ClientKeyObject,\n headers: Record<string, string>\n ): Promise<Client> {\n const [, connection] =\n [...this.#connections.entries()].find(([k]) => key === k) ?? [];\n\n if (!connection) {\n throw new Error(\"Transport not found\");\n }\n\n const type =\n connection.transportOptions.type ?? connection.transportOptions.transport;\n if (type === \"stdio\") {\n throw new Error(\"Forking stdio transport is not supported\");\n }\n\n return this.createClient(type as \"http\", key.serverName, {\n ...connection.transportOptions,\n headers,\n } as ResolvedStreamableHTTPConnection);\n }\n\n /**\n * Get the transport based on server name and connection configuration.\n * @param options - The options for the transport\n * @returns The transport\n */\n get(serverName: string): Client | undefined;\n get(options: TransportOptions): Client | undefined;\n get(options: TransportOptions | string): Client | undefined {\n if (typeof options === \"string\") {\n return this.#queryConnection({ serverName: options })?.connection.client;\n }\n\n return this.#queryConnection(options)?.connection.client;\n }\n\n /**\n * Get all clients\n * @returns All clients\n */\n getAllClients(): Client[] {\n return Array.from(this.#connections.values()).map(\n (connection) => connection.client\n );\n }\n\n /**\n * Find the connection based on the parameter provided. This approach makes sure\n * that `this.get({ serverName })` and `this.get({ serverName, headers: undefined, authProvider: undefined })`\n * will return the same connection.\n *\n * @param options - The options for the transport\n * @returns The connection and the key\n */\n #queryConnection(\n options: TransportOptions\n ): { key: ClientKeyObject; connection: Connection } | undefined {\n const headers = serializeHeaders(options.headers);\n const [key, connection] =\n [...this.#connections.entries()].find(([key]) => {\n if (options.headers && options.authProvider) {\n return (\n key.serverName === options.serverName &&\n key.headers === headers &&\n key.authProvider === options.authProvider\n );\n }\n if (options.headers && !options.authProvider) {\n return (\n key.serverName === options.serverName && key.headers === headers\n );\n }\n if (options.authProvider && !options.headers) {\n return (\n key.serverName === options.serverName &&\n key.authProvider === options.authProvider\n );\n }\n return key.serverName === options.serverName;\n }) ?? [];\n\n if (key && connection) {\n return { key, connection };\n }\n\n return undefined;\n }\n\n /**\n * Check if a client exists based on server name and connection configuration.\n * @param options - The options for the transport\n * @returns True if the client exists, false otherwise\n */\n has(serverName: string): boolean;\n has(options: TransportOptions): boolean;\n has(options: TransportOptions | string): boolean {\n return Boolean(\n typeof options === \"string\" ? this.get(options) : this.get(options)\n );\n }\n\n /**\n * Delete the transport based on server name and connection configuration.\n * @param options - The options for the transport, if not provided, all transports are deleted\n */\n async delete(options?: TransportOptions) {\n if (!options) {\n await Promise.all(\n Array.from(this.#connections.values()).map((connection) =>\n connection.closeCallback()\n )\n );\n this.#connections.clear();\n return;\n }\n\n const result = this.#queryConnection(options);\n if (result) {\n await result.connection.closeCallback();\n this.#connections.delete(result.key);\n }\n }\n\n /**\n * Get the transport for a specific client\n * @param client - The client to get the transport for\n */\n getTransport(\n client: Client\n ):\n | StreamableHTTPClientTransport\n | SSEClientTransport\n | StdioClientTransport\n | undefined;\n /**\n * Get the transport for a specific connection combination\n * @param options - The options to get the transport for\n */\n getTransport(\n options: TransportOptions\n ):\n | StreamableHTTPClientTransport\n | SSEClientTransport\n | StdioClientTransport\n | undefined;\n getTransport(\n opts: Client | TransportOptions\n ):\n | StreamableHTTPClientTransport\n | SSEClientTransport\n | StdioClientTransport\n | undefined {\n /**\n * if a client instance is passed in\n */\n if (\"listTools\" in opts) {\n const connection = [...this.#connections.values()].find(\n (connection) => connection.client === opts\n );\n return connection?.transport;\n }\n\n const result = this.#queryConnection(opts);\n if (result) {\n return result.connection.transport;\n }\n return undefined;\n }\n\n async #createStreamableHTTPTransport(\n serverName: string,\n args: ResolvedStreamableHTTPConnection\n ): Promise<StreamableHTTPClientTransport> {\n const { url, headers, reconnect, authProvider } = args;\n\n const options: StreamableHTTPClientTransportOptions = {\n ...(authProvider ? { authProvider } : {}),\n ...(headers ? { requestInit: { headers } } : {}),\n };\n\n if (reconnect != null) {\n const reconnectionOptions: StreamableHTTPReconnectionOptions = {\n initialReconnectionDelay: reconnect?.delayMs ?? 1000, // MCP default\n maxReconnectionDelay: reconnect?.delayMs ?? 30000, // MCP default\n maxRetries: reconnect?.maxAttempts ?? 2, // MCP default\n reconnectionDelayGrowFactor: 1.5, // MCP default\n };\n\n if (reconnect.enabled === false) {\n reconnectionOptions.maxRetries = 0;\n }\n\n options.reconnectionOptions = reconnectionOptions;\n }\n\n if (options.requestInit?.headers) {\n debugLog(\n `DEBUG: Using custom headers for SSE transport to server \"${serverName}\"`\n );\n }\n\n if (options.authProvider) {\n debugLog(\n `DEBUG: Using OAuth authentication for Streamable HTTP transport to server \"${serverName}\"`\n );\n }\n\n if (options.reconnectionOptions) {\n if (options.reconnectionOptions.maxRetries === 0) {\n debugLog(\n `DEBUG: Disabling reconnection for Streamable HTTP transport to server \"${serverName}\"`\n );\n } else {\n debugLog(\n `DEBUG: Using custom reconnection options for Streamable HTTP transport to server \"${serverName}\"`\n );\n }\n }\n\n // Only pass options if there are any, otherwise use default constructor\n return Object.keys(options).length > 0\n ? new StreamableHTTPClientTransport(new URL(url), options)\n : new StreamableHTTPClientTransport(new URL(url));\n }\n\n /**\n * Create an SSE transport with appropriate EventSource implementation\n *\n * @param serverName - The name of the server\n * @param url - The URL of the server\n * @param headers - The headers to send with the request\n * @param authProvider - The OAuth client provider to use for authentication\n * @returns The SSE transport\n */\n async #createSSETransport(\n serverName: string,\n args: ResolvedStreamableHTTPConnection\n ): Promise<SSEClientTransport> {\n const { url, headers, authProvider } = args;\n const options: SSEClientTransportOptions = {};\n\n if (authProvider) {\n options.authProvider = authProvider;\n debugLog(\n `DEBUG: Using OAuth authentication for SSE transport to server \"${serverName}\"`\n );\n }\n\n if (headers) {\n // For SSE, we need to pass headers via eventSourceInit.fetch for the initial connection\n // and also via requestInit.headers for subsequent POST requests\n options.eventSourceInit = {\n fetch: async (url, init) => {\n const requestHeaders = new Headers(init?.headers);\n\n // Add OAuth token if authProvider is available\n // This is necessary because setting eventSourceInit.fetch prevents automatic Authorization header\n if (authProvider) {\n const tokens = await authProvider.tokens();\n if (tokens) {\n requestHeaders.set(\n \"Authorization\",\n `Bearer ${tokens.access_token}`\n );\n }\n }\n\n // Add our custom headers\n Object.entries(headers).forEach(([key, value]) => {\n requestHeaders.set(key, value);\n });\n // Always include Accept header for SSE\n requestHeaders.set(\"Accept\", \"text/event-stream\");\n\n return fetch(url, {\n ...init,\n headers: requestHeaders,\n });\n },\n };\n\n // Also include headers for POST requests\n options.requestInit = { headers };\n\n debugLog(\n `DEBUG: Using custom headers for SSE transport to server \"${serverName}\"`\n );\n }\n\n return new SSEClientTransport(new URL(url), options);\n }\n\n #createStdioTransport(\n options: ResolvedStdioConnection\n ): StdioClientTransport {\n const { command, args, env, stderr, cwd } = options;\n return new StdioClientTransport({\n command,\n args,\n stderr,\n cwd,\n // eslint-disable-next-line no-process-env\n ...(env ? { env: { PATH: process.env.PATH!, ...env } } : {}),\n });\n }\n}\n\n/**\n * A utility function that serializes the headers object to a string\n * and orders the keys alphabetically so that the same headers object\n * will always produce the same string.\n * @param headers - The headers object to serialize\n * @returns The serialized headers object\n */\nfunction serializeHeaders(\n headers?: Record<string, string>\n): string | undefined {\n if (!headers) {\n return;\n }\n return Object.entries(headers)\n .sort(([a], [b]) => a.localeCompare(b))\n .map(([key, value]) => `${key}: ${value}`)\n .join(\"\\n\");\n}\n"],"mappings":"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"}