UNPKG

@toolprint/hypertool-mcp

Version:

HyperTool MCP proxy server for routing requests between clients and multiple underlying MCP servers

149 lines • 4.1 kB
/** * SSE client implementation for connecting to external MCP servers using official MCP SDK * This is used when the Meta-MCP server acts as a CLIENT to SSE-based MCP servers (like Context7) */ import { Client } from "@modelcontextprotocol/sdk/client/index.js"; import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js"; import { EventEmitter } from "events"; import { BaseConnection } from "./base.js"; import { createChildLogger } from "../../utils/logging.js"; const logger = createChildLogger({ module: "clients/sse" }); /** * SSE client wrapper using proper MCP SDK Client */ export class SSEClient extends EventEmitter { config; client = null; isConnected = false; constructor(config) { super(); this.config = config; } /** * Connect to the SSE-based MCP server using SDK Client */ async connect() { if (this.isConnected) { return; } try { const transport = new SSEClientTransport(new URL(this.config.url)); this.client = new Client({ name: "hypertool-mcp-client", version: "1.0.0", }, { capabilities: { tools: {}, }, }); await this.client.connect(transport); this.isConnected = true; this.emit("connected"); } catch (error) { this.client = null; throw new Error(`Failed to connect SSE client: ${error.message}`); } } /** * Disconnect from the SSE server */ async disconnect() { if (!this.client) { return; } try { await this.client.close(); } catch (error) { logger.error("Error closing SSE client:", error); } finally { this.client = null; this.isConnected = false; } } /** * List tools from the MCP server */ async listTools() { if (!this.client) { throw new Error("Client not connected"); } return await this.client.listTools(); } /** * Call a tool on the MCP server */ async callTool(params) { if (!this.client) { throw new Error("Client not connected"); } return await this.client.callTool(params); } /** * Get the SDK client instance for advanced operations */ get sdkClient() { return this.client; } } /** * SSE connection implementation */ export class SSEConnection extends BaseConnection { _client = null; constructor(serverName, config, options = {}) { super(serverName, config, options); } /** * Create and return SSE client */ createClient() { return new SSEClient(this.config); } /** * Connect to the SSE server */ async doConnect() { this._client = new SSEClient(this.config); // Forward client events this._client.on("error", (error) => { this.emit("error", this.createEvent("error", { error })); }); this._client.on("disconnected", () => { this.emit("disconnected", this.createEvent("disconnected")); }); this._client.on("message", (message) => { this.emit("message", message); }); await this._client.connect(); } /** * Disconnect from the SSE server */ async doDisconnect() { if (this._client) { await this._client.disconnect(); this._client = null; } } /** * Ping the SSE server */ async doPing() { if (!this._client) { return false; } try { // Use SDK client to ping - may not have a direct ping method, // so we can try listing tools as a health check await this._client.listTools(); return true; } catch { return false; } } } //# sourceMappingURL=sse.js.map