UNPKG

@toolprint/hypertool-mcp

Version:

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

155 lines • 4.08 kB
/** * Stdio client implementation for MCP servers using official MCP SDK */ import { Client } from "@modelcontextprotocol/sdk/client/index.js"; import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js"; import { EventEmitter } from "events"; import { BaseConnection } from "./base.js"; import { createChildLogger } from "../../utils/logging.js"; const logger = createChildLogger({ module: "clients/stdio" }); /** * Stdio client wrapper using proper MCP SDK Client */ export class StdioClient extends EventEmitter { config; client = null; isConnected = false; constructor(config) { super(); this.config = config; } get isRunning() { return this.isConnected && this.client !== null; } /** * Start the MCP server process using SDK Client */ async start() { if (this.isRunning) { return; } try { const transport = new StdioClientTransport({ command: this.config.command, args: this.config.args, env: this.config.env, }); this.client = new Client({ name: "hypertool-mcp-client", version: "1.0.0", }, { capabilities: { tools: {}, }, }); await this.client.connect(transport); this.isConnected = true; } catch (error) { this.client = null; throw new Error(`Failed to start stdio client: ${error.message}`); } } /** * Stop the MCP server process */ async stop() { if (!this.client) { return; } try { await this.client.close(); } catch (error) { logger.error("Error closing stdio 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); } /** * Ping the server to check if it's responsive */ async ping() { if (!this.isRunning) { return false; } try { await this.listTools(); return true; } catch { return false; } } /** * Get the SDK client instance for advanced operations */ get sdkClient() { return this.client; } } /** * Stdio connection implementation */ export class StdioConnection extends BaseConnection { _client = null; constructor(serverName, config, options = {}) { super(serverName, config, options); } /** * Connect to the stdio server */ async doConnect() { this._client = new StdioClient(this.config); // Forward client events this._client.on("error", (error) => { this.emit("error", this.createEvent("error", { error })); }); this._client.on("disconnect", () => { this.emit("disconnected", this.createEvent("disconnected")); }); this._client.on("message", (message) => { this.emit("message", message); }); await this._client.start(); } /** * Disconnect from the stdio server */ async doDisconnect() { if (this._client) { await this._client.stop(); this._client = null; } } /** * Ping the stdio server */ async doPing() { if (!this._client) { return false; } return await this._client.ping(); } } //# sourceMappingURL=stdio.js.map