UNPKG

@agentpaid/mcp-use

Version:

A utility library for integrating Model Context Protocol (MCP) with LangChain, Zod, and related tools. Provides helpers for schema conversion, event streaming, and SDK usage.

155 lines (154 loc) 6.65 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.HttpConnector = void 0; const index_js_1 = require("@modelcontextprotocol/sdk/client/index.js"); const streamableHttp_js_1 = require("@modelcontextprotocol/sdk/client/streamableHttp.js"); const logging_js_1 = require("../logging.js"); const sse_js_1 = require("../task_managers/sse.js"); const streamable_http_js_1 = require("../task_managers/streamable_http.js"); const base_js_1 = require("./base.js"); class HttpConnector extends base_js_1.BaseConnector { baseUrl; headers; timeout; sseReadTimeout; clientInfo; preferSse; transportType = null; constructor(baseUrl, opts = {}) { super(opts); this.baseUrl = baseUrl.replace(/\/$/, ''); this.headers = { ...(opts.headers ?? {}) }; if (opts.authToken) { this.headers.Authorization = `Bearer ${opts.authToken}`; } this.timeout = opts.timeout ?? 5; this.sseReadTimeout = opts.sseReadTimeout ?? 60 * 5; this.clientInfo = opts.clientInfo ?? { name: 'http-connector', version: '1.0.0' }; this.preferSse = opts.preferSse ?? false; } /** Establish connection to the MCP implementation via HTTP (streamable or SSE). */ async connect() { if (this.connected) { logging_js_1.logger.debug('Already connected to MCP implementation'); return; } const baseUrl = this.baseUrl; // If preferSse is set, skip directly to SSE if (this.preferSse) { logging_js_1.logger.debug(`Connecting to MCP implementation via HTTP/SSE: ${baseUrl}`); await this.connectWithSse(baseUrl); return; } // Try streamable HTTP first, then fall back to SSE logging_js_1.logger.debug(`Connecting to MCP implementation via HTTP: ${baseUrl}`); try { // Try streamable HTTP transport first logging_js_1.logger.debug('Attempting streamable HTTP transport...'); await this.connectWithStreamableHttp(baseUrl); } catch (err) { // Check if this is a 4xx error that indicates we should try SSE fallback let fallbackReason = 'Unknown error'; if (err instanceof streamableHttp_js_1.StreamableHTTPError) { if (err.code === 404 || err.code === 405) { fallbackReason = `Server returned ${err.code} - server likely doesn't support streamable HTTP`; logging_js_1.logger.debug(fallbackReason); } else { fallbackReason = `Server returned ${err.code}: ${err.message}`; logging_js_1.logger.debug(fallbackReason); } } else if (err instanceof Error) { // Check for 404/405 in error message as fallback detection const errorStr = err.toString(); if (errorStr.includes('405 Method Not Allowed') || errorStr.includes('404 Not Found')) { fallbackReason = 'Server doesn\'t support streamable HTTP (405/404)'; logging_js_1.logger.debug(fallbackReason); } else { fallbackReason = `Streamable HTTP failed: ${err.message}`; logging_js_1.logger.debug(fallbackReason); } } // Always try SSE fallback for maximum compatibility logging_js_1.logger.debug('Falling back to SSE transport...'); try { await this.connectWithSse(baseUrl); } catch (sseErr) { logging_js_1.logger.error(`Failed to connect with both transports:`); logging_js_1.logger.error(` Streamable HTTP: ${fallbackReason}`); logging_js_1.logger.error(` SSE: ${sseErr}`); await this.cleanupResources(); throw new Error('Could not connect to server with any available transport'); } } } async connectWithStreamableHttp(baseUrl) { try { // Create and start the streamable HTTP connection manager this.connectionManager = new streamable_http_js_1.StreamableHttpConnectionManager(baseUrl, { requestInit: { headers: this.headers, }, // Pass through timeout and other options reconnectionOptions: { maxReconnectionDelay: 30000, initialReconnectionDelay: 1000, reconnectionDelayGrowFactor: 1.5, maxRetries: 2, }, }); const transport = await this.connectionManager.start(); // Create and connect the client this.client = new index_js_1.Client(this.clientInfo, this.opts.clientOptions); await this.client.connect(transport); this.connected = true; this.transportType = 'streamable-http'; logging_js_1.logger.debug(`Successfully connected to MCP implementation via streamable HTTP: ${baseUrl}`); } catch (err) { // Clean up partial resources before throwing await this.cleanupResources(); throw err; } } async connectWithSse(baseUrl) { try { // Create and start the SSE connection manager this.connectionManager = new sse_js_1.SseConnectionManager(baseUrl, { requestInit: { headers: this.headers, }, }); const transport = await this.connectionManager.start(); // Create and connect the client this.client = new index_js_1.Client(this.clientInfo, this.opts.clientOptions); await this.client.connect(transport); this.connected = true; this.transportType = 'sse'; logging_js_1.logger.debug(`Successfully connected to MCP implementation via HTTP/SSE: ${baseUrl}`); } catch (err) { // Clean up partial resources before throwing await this.cleanupResources(); throw err; } } get publicIdentifier() { return { type: 'http', url: this.baseUrl, transport: this.transportType || 'unknown', }; } /** * Get the transport type being used (streamable-http or sse) */ getTransportType() { return this.transportType; } } exports.HttpConnector = HttpConnector;