Skip to main content
Glama
index.ts12.3 kB
#!/usr/bin/env node /** * code2mcp - Code Mode MCP Server * * Implements Cloudflare's Code Mode pattern: convert MCP tools to TypeScript APIs * and have LLMs write code instead of making direct tool calls. * * Benefits: * - 98% token reduction for complex workflows * - Better tool understanding (LLMs trained on TypeScript) * - Secure sandbox execution * - API keys hidden from LLM-generated code */ import { Server } from "@modelcontextprotocol/sdk/server/index.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js"; import { MCPOrchestrator } from "./orchestrator/MCPOrchestrator.js"; import { TypeScriptGenerator } from "./generator/TypeScriptGenerator.js"; import { CodeSandbox } from "./sandbox/CodeSandbox.js"; import type { MCPServerConfig } from "./types/index.js"; import { logInfo, logError } from "./utils/logger.js"; import { fileURLToPath } from "url"; import { dirname, join } from "path"; import { readFileSync } from "fs"; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); // Load configuration from mcp-servers.config.js const configPath = join(__dirname, "..", "mcp-servers.config.js"); let serverConfig: any; try { let configModule = readFileSync(configPath, "utf-8"); console.log("[DEBUG] Raw config length:", configModule.length); // Strip out JavaScript comments for eval compatibility configModule = configModule.replace(/\/\*[\s\S]*?\*\//g, ''); // Remove block comments configModule = configModule.replace(/\/\/.*$/gm, ''); // Remove line comments console.log("[DEBUG] After removing comments:", configModule.length); // Replace process.env references with actual values or defaults configModule = configModule.replace(/process\.env\.(\w+)\s*\|\|\s*["']([^"']*)["']/g, (_match, envVar, defaultVal) => { return `"${process.env[envVar] || defaultVal}"`; }); configModule = configModule.replace(/process\.env\.(\w+)/g, (_match, envVar) => { return `"${process.env[envVar] || ''}"`; }); // Remove "module.exports = " and trim whitespace let configStr = configModule.replace("module.exports =", "").trim(); // Remove all semicolons (they're not needed in object literals) configStr = configStr.replace(/;/g, ''); // Split into lines, trim each, and rejoin const lines = configStr.split('\n') .map(line => line.trim()) .filter(line => line.length > 0); configStr = lines.join('\n'); console.log("[DEBUG] Final config string length:", configStr.length); console.log("[DEBUG] Config:\n", configStr); // Wrap in parentheses to make it a valid expression and evaluate try { serverConfig = eval(configStr); } catch (e1: any) { console.log("[DEBUG] First eval failed, trying with parentheses:", e1?.message); serverConfig = eval("(" + configStr + ")"); } logInfo("Successfully loaded mcp-servers.config.js", {}); } catch (error) { console.log("[DEBUG] Config load error:", error instanceof Error ? error.message : String(error)); logError("Failed to load mcp-servers.config.js, using defaults", { error: error instanceof Error ? error.message : String(error), }); serverConfig = { servers: { context7: { enabled: true, command: "npx", args: ["-y", "@upstash/context7-mcp"] }, playwright: { enabled: true, command: "npx", args: ["@playwright/mcp@latest"] }, brightData: { enabled: true, command: "npx", args: ["@brightdata/mcp"], env: {} }, chromeDevtools: { enabled: true, command: "npx", args: ["chrome-devtools-mcp@latest"] }, firecrawl: { enabled: true, command: "npx", args: ["-y", "firecrawl-mcp"], env: {} }, shadcn: { enabled: true, command: "npx", args: ["-y", "mcp-remote", "https://www.shadcn.io/api/mcp"] }, }, }; } // Build MCP_SERVERS array from config (only enabled servers) const MCP_SERVERS: MCPServerConfig[] = []; // Map config keys to server names for MCP protocol const serverNameMap: Record<string, string> = { context7: "context7", playwright: "playwright", brightData: "bright-data", chromeDevtools: "chrome-devtools", firecrawl: "firecrawl-mcp", shadcn: "shadcn", }; for (const [key, config] of Object.entries(serverConfig.servers)) { const cfg = config as any; // Type assertion for dynamic config if (cfg.enabled) { const serverName = serverNameMap[key] || key; MCP_SERVERS.push({ name: serverName, transport: "stdio", command: cfg.command, args: cfg.args, env: cfg.env || {}, }); } } logInfo("Loaded MCP server configuration", { totalServers: Object.keys(serverConfig.servers).length, enabledServers: MCP_SERVERS.length, servers: MCP_SERVERS.map((s) => s.name), }); async function main() { logInfo("Starting code2mcp server"); // Initialize components const orchestrator = new MCPOrchestrator(); const generator = new TypeScriptGenerator(); // Connect to MCP servers logInfo("Connecting to MCP servers", { count: MCP_SERVERS.length }); for (const serverConfig of MCP_SERVERS) { try { await orchestrator.connectServer(serverConfig); } catch (error) { logError("Failed to connect to MCP server, continuing without it", { server: serverConfig.name, error: error instanceof Error ? error.message : String(error), }); } } // Get all tools const allTools = orchestrator.getAllTools(); logInfo("Fetched tools from MCP servers", { toolCount: allTools.length, servers: orchestrator.getServerNames(), }); // Generate TypeScript APIs if (allTools.length > 0) { await generator.generateAPIs(allTools, "generated"); logInfo("Generated TypeScript APIs"); } else { logInfo("No tools available, skipping API generation"); } // Initialize sandbox const sandbox = new CodeSandbox(orchestrator); // Create MCP server const server = new Server( { name: "code2mcp", version: "1.0.0", }, { capabilities: { tools: {}, }, }, ); // List tools handler - expose only execute_code server.setRequestHandler(ListToolsRequestSchema, async () => { const apiDocs = generateAPIDocumentation(allTools); return { tools: [ { name: "execute_code", description: `Execute TypeScript code with access to MCP tool APIs. **Available APIs:** ${apiDocs} The code will run in a secure sandbox with: - No network access - No filesystem access - Access only to MCP tool APIs - console.log() output will be returned to you **Example Usage:** \`\`\`typescript // Example: Call a single tool const result = await __mcp_call('server__tool_name', { param: 'value' }); console.log('Result:', result); \`\`\` **Multi-step workflow example:** \`\`\`typescript // Fetch data from one service const data = await __mcp_call('service1__get_data', { id: '123' }); // Process and send to another service await __mcp_call('service2__update', { value: data.content }); console.log('Workflow complete'); \`\`\` **Note:** Intermediate data stays in the sandbox (doesn't enter your context), saving massive amounts of tokens for complex workflows.`, inputSchema: { type: "object", properties: { code: { type: "string", description: "TypeScript code to execute in the sandbox", }, timeout: { type: "number", description: "Timeout in milliseconds (default: 30000)", default: 30000, }, }, required: ["code"], }, }, ], }; }); // Execute code handler server.setRequestHandler(CallToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; if (name !== "execute_code") { throw new Error(`Unknown tool: ${name}`); } const { code, timeout } = args as { code: string; timeout?: number }; if (!code || typeof code !== "string") { throw new Error("Code parameter is required and must be a string"); } logInfo("Executing code", { codeLength: code.length, timeout: timeout || 30000, }); try { const result = await sandbox.execute(code, { timeout }); if (result.error) { const errorOutput = [ "=== Execution Error ===", result.error, "", "=== Logs ===", ...result.logs, "", `Execution time: ${result.executionTime}ms`, ].join("\n"); return { content: [ { type: "text", text: errorOutput, }, ], isError: true, }; } const output = [ "=== Execution Logs ===", ...result.logs, "", "=== Result ===", result.result !== undefined ? JSON.stringify(result.result, null, 2) : "(undefined)", "", `Execution time: ${result.executionTime}ms`, ].join("\n"); return { content: [ { type: "text", text: output, }, ], }; } catch (error) { logError("Sandbox execution failed", { error: error instanceof Error ? error.message : String(error), }); return { content: [ { type: "text", text: `Sandbox Error: ${error instanceof Error ? error.message : String(error)}`, }, ], isError: true, }; } }); // Start server const transport = new StdioServerTransport(); await server.connect(transport); logInfo("code2mcp server started successfully", { toolCount: allTools.length, servers: orchestrator.getServerNames(), }); // Graceful shutdown process.on("SIGINT", async () => { logInfo("Shutting down..."); await orchestrator.disconnect(); process.exit(0); }); process.on("SIGTERM", async () => { logInfo("Shutting down..."); await orchestrator.disconnect(); process.exit(0); }); } /** * Generate API documentation for the tool description * Now includes parameter information to help Claude understand tool signatures */ function generateAPIDocumentation(tools: any[]): string { if (tools.length === 0) { return "No MCP servers connected. Configure servers in src/index.ts"; } // Group tools by server const byServer = new Map<string, any[]>(); for (const tool of tools) { const parts = tool.name.split("__"); if (parts.length < 2) continue; const serverName = parts[0]; if (!byServer.has(serverName)) { byServer.set(serverName, []); } byServer.get(serverName)!.push(tool); } let doc = ""; for (const [serverName, serverTools] of byServer) { doc += `\n**${serverName}**:\n`; for (const tool of serverTools) { // Extract parameter information from input schema const params = extractParameters(tool.inputSchema); doc += ` - \`__mcp_call('${tool.name}', {${params .map((p) => { const paramName = p.split(":")[0].trim(); return `${paramName}: value`; }) .join(", ")}})\`\n`; doc += ` ${tool.description || "No description"}\n`; if (params.length > 0) { doc += ` Parameters: ${params.join(", ")}\n`; } } } return doc; } /** * Extract parameter information from JSON Schema */ function extractParameters(schema: any): string[] { if (!schema || !schema.properties) { return []; } const params: string[] = []; const required = schema.required || []; for (const [name, prop] of Object.entries(schema.properties)) { const propSchema = prop as any; const type = propSchema.type || "any"; const isRequired = required.includes(name); const optional = isRequired ? "" : "?"; params.push(`${name}${optional}: ${type}`); } return params; } // Run the server main().catch((error) => { logError("Fatal error", { error: error instanceof Error ? error.message : String(error), stack: error instanceof Error ? error.stack : undefined, }); process.exit(1); });

Implementation Reference

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/blas0/code2mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server