UNPKG

@idealyst.ai/mcp-server

Version:

Model Context Protocol server for Idealyst MVP pipeline assets

201 lines 7.57 kB
#!/usr/bin/env node /** * Idealyst MCP Server Bridge * * Bridges HTTP-based Idealyst MCP server with stdio transport for Claude Code. * This allows the remote server to work with MCP clients expecting stdio. */ import { Server } from "@modelcontextprotocol/sdk/server/index.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { CallToolRequestSchema, ListToolsRequestSchema, ListResourcesRequestSchema, ReadResourceRequestSchema } from "@modelcontextprotocol/sdk/types.js"; class IdealystMCPBridge { server; config; transport; constructor() { // Get configuration from environment variables this.config = { url: process.env.IDEALYST_MCP_URL || "https://138.197.11.162/mcp", token: process.env.IDEALYST_MCP_TOKEN || "" }; if (!this.config.token) { console.error("❌ Error: IDEALYST_MCP_TOKEN environment variable required"); process.exit(1); } // Initialize MCP server this.server = new Server({ name: "idealyst-mcp-server", version: "1.0.0" }, { capabilities: { tools: {}, resources: {} } }); this.setupHandlers(); } async makeRequest(endpoint, options) { const url = `${this.config.url.replace(/\/$/, "")}${endpoint}`; // Import node-fetch and https dynamically for ESM compatibility const fetch = (await import("node-fetch")).default; const https = await import("https"); // Create an agent that ignores self-signed certificates const agent = new https.Agent({ rejectUnauthorized: false }); const response = await fetch(url, { method: options?.method || "GET", headers: { "Authorization": `Bearer ${this.config.token}`, "Content-Type": "application/json", ...options?.headers }, body: options?.body ? JSON.stringify(options.body) : undefined, follow: 20, // Follow up to 20 redirects redirect: "follow", // Explicitly enable redirect following // Use the agent for HTTPS requests agent: url.startsWith("https") ? agent : undefined }); if (response.ok) { return await response.json(); } else { const errorText = await response.text(); throw new Error(`HTTP ${response.status}: ${errorText}`); } } setupHandlers() { // Handle tool listing this.server.setRequestHandler(ListToolsRequestSchema, async () => { try { const data = await this.makeRequest("/tools"); const tools = (data.tools || []).map((tool) => ({ name: tool.name, description: tool.description || "", inputSchema: tool.inputSchema || { type: "object", properties: {}, required: [] } })); return { tools }; } catch (error) { console.error("❌ Failed to list tools:", error); return { tools: [] }; } }); // Handle tool execution this.server.setRequestHandler(CallToolRequestSchema, async (request) => { try { const result = await this.makeRequest("/tools/execute", { method: "POST", body: { name: request.params.name, arguments: request.params.arguments } }); const content = [ { type: "text", text: typeof result === "string" ? result : JSON.stringify(result, null, 2) } ]; return { content }; } catch (error) { console.error(`❌ Failed to execute tool ${request.params.name}:`, error); return { content: [ { type: "text", text: `Error executing tool: ${error}` } ] }; } }); // Handle resource listing (optional - returns empty if not implemented) this.server.setRequestHandler(ListResourcesRequestSchema, async () => { try { const data = await this.makeRequest("/resources"); const resources = (data.resources || []).map((resource) => ({ uri: resource.uri, name: resource.name || "", description: resource.description, mimeType: resource.mimeType || "text/plain" })); return { resources }; } catch (error) { // Resources endpoint not implemented is okay return { resources: [] }; } }); // Handle resource reading this.server.setRequestHandler(ReadResourceRequestSchema, async (request) => { try { const resourcePath = `/resources/${encodeURIComponent(request.params.uri)}`; const data = await this.makeRequest(resourcePath); return { contents: [ { uri: request.params.uri, mimeType: "text/plain", text: data.content || JSON.stringify(data, null, 2) } ] }; } catch (error) { console.error(`❌ Failed to read resource ${request.params.uri}:`, error); return { contents: [ { uri: request.params.uri, mimeType: "text/plain", text: `Error reading resource: ${error}` } ] }; } }); } async run() { try { // Test connection to Idealyst MCP server await this.makeRequest("/health"); console.error("✅ Connected to Idealyst MCP Server"); // Create and connect stdio transport this.transport = new StdioServerTransport(); await this.server.connect(this.transport); console.error("🚀 Idealyst MCP Bridge running"); } catch (error) { console.error("❌ Bridge failed:", error); process.exit(1); } } } // Main entry point async function main() { console.error("🚀 Starting Idealyst MCP Bridge..."); console.error("🔗 Bridging HTTP MCP server to stdio for Claude Code"); const bridge = new IdealystMCPBridge(); await bridge.run(); } // Handle graceful shutdown process.on("SIGINT", () => { console.error("\n🛑 Shutting down bridge..."); process.exit(0); }); process.on("SIGTERM", () => { console.error("\n🛑 Shutting down bridge..."); process.exit(0); }); // Run the bridge main().catch((error) => { console.error("❌ Fatal error:", error); process.exit(1); }); //# sourceMappingURL=index.js.map