Skip to main content
Glama
Mulan Permissive Software License, Version 2
2
  • Linux
  • Apple
createMcpServer.js13.2 kB
import { JSONSchemaToZod } from "@dmitryrechkin/json-schema-to-zod"; import { Client } from "@modelcontextprotocol/sdk/client/index.js"; import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { CallToolRequestSchema, GetPromptRequestSchema, ListPromptsRequestSchema, ListResourcesRequestSchema, ListResourceTemplatesRequestSchema, ListToolsRequestSchema, ReadResourceRequestSchema, SetLevelRequestSchema, } from "@modelcontextprotocol/sdk/types.js"; import { getServerCapabilities } from "./getServerCapabilities.js"; import {} from "./main.js"; import { setupAllNotificationHandlers } from "./notificationHandlers.js"; import { selectTransport } from "./selectTransport.js"; export async function createMcpServer(serverName, serverConfig) { let transport = selectTransport(serverConfig); if (transport) { console.log("transport", transport); transport.onclose = () => { console.log(`[${serverName}] Transport connection closed`); }; } if (!transport) { throw new Error("Failed to create transport, please check the configuration."); } console.log("clienttransport", transport); transport.onclose = () => { console.log(`[${serverName}] Transport connection closed`); }; transport.onerror = (error) => { console.error(`[${serverName}] Transport connection error:`, error); }; const client = new Client({ name: `bridge-client-${serverName}`, version: "1.0.0" }, { capabilities: { tools: {}, resources: {}, prompts: {}, }, }); client.onclose = () => { console.log(`[${serverName}] Transport connection closed`); }; client.onerror = (error) => { console.error(`[${serverName}] Transport connection error:`, error); }; try { const connectPromise = client.connect(transport); const timeoutPromise = new Promise((_, reject) => { setTimeout(() => reject(new Error("Connection timeout")), 10000); }); await Promise.race([connectPromise, timeoutPromise]); } catch (error) { console.error(`[${serverName}] Error connecting to server:`, error); try { transport?.close?.(); } catch (cleanupError) { console.warn(`[${serverName}] Error cleaning up transport:`, cleanupError); } return null; } console.log("client connected", transport); const capabilities = (await getServerCapabilities(client)) ?? {}; console.log(`[${serverName}] capabilities:`, capabilities); const listOutputs = { tools: null, prompts: null, resources: null, resourceTemplates: null, }; try { const tools = await client.listTools(); console.log(`[${serverName}] Registering tools:`, JSON.stringify(tools, null, 4)); listOutputs.tools = tools; capabilities.tools = { listChanged: true, }; } catch (error) { console.error(`[${serverName}] Error listing tools:`, error); capabilities.tools = undefined; } if ((await getServerCapabilities(client))?.prompts) { try { const prompts = await client.listPrompts(); console.log(`[${serverName}] Registering prompts:`, JSON.stringify(prompts, null, 4)); listOutputs.prompts = prompts; capabilities.prompts = { listChanged: true, }; } catch (error) { console.error(`[${serverName}] Error listing prompts:`, error); capabilities.prompts = undefined; } } if ((await getServerCapabilities(client))?.resources) { try { const Resources = await client.listResources(); console.log(`[${serverName}] Registering Resources:`, JSON.stringify(Resources, null, 4)); listOutputs.resources = Resources; capabilities.resources = { listChanged: true, }; } catch (error) { console.error(`[${serverName}] Error listing Resources:`, error); capabilities.resources = undefined; if (listOutputs.resources || listOutputs.resourceTemplates) { capabilities.resources = {}; } } } if ((await getServerCapabilities(client))?.resources) { try { const ResourcesTemplates = await client.listResourceTemplates(); console.log(`[${serverName}] Registering ResourcesTemplates:`, JSON.stringify(ResourcesTemplates, null, 4)); listOutputs.resourceTemplates = ResourcesTemplates; capabilities.resources = { listChanged: true, }; } catch (error) { console.error(`[${serverName}] Error listing ResourcesTemplates:`, error); if (String(error).includes("McpError: MCP error -32001: Request timed out")) { throw error; } capabilities.resources = undefined; if (listOutputs.resources || listOutputs.resourceTemplates) { capabilities.resources = {}; } } } const server = new McpServer({ name: `bridge-service-${serverName}`, version: "1.0.0", }, { capabilities: Object.assign(capabilities, { tools: { listChanged: true }, }), }); try { if (capabilities.tools && listOutputs.tools) { server.server.registerCapabilities({ tools: { listChanged: true }, }); const tools = listOutputs.tools; await Promise.all(tools.tools.map(async (tool) => { console.log(`[${serverName}] Registering tool: `, JSON.stringify({ name: tool.name, description: tool.description, annotations: tool.annotations, }, null, 4)); const inputSchema = JSONSchemaToZod.convert(tool.inputSchema).shape; const outputSchema = tool.outputSchema ? JSONSchemaToZod.convert(tool.outputSchema).shape : tool.outputSchema; server.registerTool(tool.name, { description: tool.description, annotations: tool.annotations, ...tool, inputSchema: inputSchema, outputSchema, }, async (params) => { console.log(`[${serverName}] Calling tool`, JSON.stringify({ name: tool.name, params }, null, 4)); const result = await client.callTool({ name: tool.name, arguments: params, }); return result; }); })); } } catch (error) { console.error(`[${serverName}] Error Registering tools:`, error); } try { if (capabilities.prompts && listOutputs.prompts) { server.server.setRequestHandler(ListPromptsRequestSchema, async () => { console.log(`[${serverName}] Listing prompts...`); return listOutputs.prompts; }); server.server.setRequestHandler(GetPromptRequestSchema, async (request) => { console.log(`[${serverName}] Getting prompt...`, JSON.stringify(request.params, null, 4)); const result = await client.getPrompt(request.params); return result; }); } } catch (error) { console.error(`[${serverName}] Error Registering prompts:`, error); } try { if (capabilities.resources && listOutputs.resources) { server.server.setRequestHandler(ReadResourceRequestSchema, async (request) => { console.log(`[${serverName}] Reading resource...`, JSON.stringify(request.params, null, 4)); const result = await client.readResource(request.params); return result; }); server.server.setRequestHandler(ListResourcesRequestSchema, async (request) => { console.log(`[${serverName}] Listing resources...`, JSON.stringify(request.params, null, 4)); return listOutputs.resources; }); server.server.setRequestHandler(ListResourceTemplatesRequestSchema, async (request) => { console.log(`[${serverName}] Listing resourceTemplates...`, JSON.stringify(request.params, null, 4)); return listOutputs.resourceTemplates; }); } } catch (error) { console.error(`[${serverName}] Error Registering Resources:`, error); } console.log("getServerCapabilities", client.getServerCapabilities()); if (client.getServerCapabilities()?.logging) { server.server.setRequestHandler(SetLevelRequestSchema, async (args) => { console.log(`[${serverName}] Setting logging level...`, JSON.stringify(args.params, null, 4)); return await client.setLoggingLevel(args.params.level); }); } server.server.setRequestHandler(ListToolsRequestSchema, async (request, extra) => { console.log(`[${serverName}] Listing tools...`, JSON.stringify(request.params, null, 4)); const tools = await client.listTools(request.params); return tools; }); server.server.setRequestHandler(CallToolRequestSchema, async (request, extra) => { console.log(`[${serverName}] Calling tool...`, JSON.stringify(request.params, null, 4)); const tools = await client.callTool(request.params); return tools; }); setupAllNotificationHandlers(client, server, serverName); client.onerror = (error) => { console.error(`[${serverName}] Client error:`, error); try { } catch (e) { console.error(`[${serverName}] Error in error handler:`, e); } }; client.onclose = async () => { console.log(`[${serverName}] Connection closed`); let retryCount = 0; const maxRetries = 3; const retryDelay = 1000; const tryReconnect = async () => { try { console.log(`[${serverName}] Attempting to reconnect... (attempt ${retryCount + 1}/${maxRetries})`); if (transport) { try { transport.close?.(); } catch (e) { console.warn(`[${serverName}] Error closing old transport:`, e); } } transport = selectTransport(serverConfig); if (transport) { console.log("transport", transport); transport.onclose = () => { console.log(`[${serverName}] Transport connection closed`); }; } if (!transport) { console.error(`[${serverName}] Failed to create transport, please check the configuration.`); return; } transport.onclose = () => { console.log(`[${serverName}] Transport connection closed`); }; transport.onerror = (error) => { console.error(`[${serverName}] Transport connection error:`, error); }; const connectPromise = client.connect(transport); const timeoutPromise = new Promise((_, reject) => { setTimeout(() => reject(new Error("Reconnection timeout")), 5000); }); await Promise.race([connectPromise, timeoutPromise]); console.log(`[${serverName}] Reconnected successfully`); } catch (error) { retryCount++; console.error(`[${serverName}] Reconnection attempt ${retryCount} failed:`, error); try { transport?.close?.(); } catch (cleanupError) { console.warn(`[${serverName}] Error cleaning up transport during reconnect:`, cleanupError); } if (retryCount < maxRetries) { console.log(`[${serverName}] Retrying in ${retryDelay}ms...`); setTimeout(tryReconnect, retryDelay * retryCount); } else { console.error(`[${serverName}] Maximum reconnection attempts (${maxRetries}) reached. Giving up.`); } } }; setImmediate(() => { try { tryReconnect(); } catch (error) { console.error(`[${serverName}] Error during reconnection setup:`, error); } }); }; return { config: serverConfig, server, client, transport: transport, httpTransports: null, }; } //# sourceMappingURL=createMcpServer.js.map

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/masx200/mcp-demo-streamable-http-bridge'

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