@idealyst.ai/mcp-server
Version:
Model Context Protocol server for Idealyst MVP pipeline assets
201 lines • 7.57 kB
JavaScript
/**
* 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