gcharanteja
feat: add intelligent routing functionality with natural language processing for knowledge management
b008b07 | import http from "node:http"; | |
| import fs from "node:fs"; | |
| import path from "node:path"; | |
| import { Server } from "@modelcontextprotocol/sdk/server/index.js"; | |
| import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js"; | |
| import { | |
| ListToolsRequestSchema, | |
| CallToolRequestSchema, | |
| } from "@modelcontextprotocol/sdk/types.js"; | |
| import { vectorTools, handleVectorTool } from "./tools/vectorTool.js"; | |
| import { curateTools, handleCurateTool } from "./tools/curateTool.js"; | |
| import { routerTools, handleRouterTool } from "./tools/routerTool.js"; | |
| const PORT = Number(process.env.PORT || 3000); | |
| const HOST = process.env.HOST || "0.0.0.0"; | |
| const DATA_DIR = process.env.DATA_DIR || "/data"; | |
| const CONFIG_PATH = path.join(DATA_DIR, "config.json"); | |
| function loadConfig() { | |
| try { | |
| if (!fs.existsSync(CONFIG_PATH)) { | |
| console.error(`Config file not found at ${CONFIG_PATH}`); | |
| process.exit(1); | |
| } | |
| const config = JSON.parse(fs.readFileSync(CONFIG_PATH, "utf8")); | |
| return config; | |
| } catch (error) { | |
| console.error(`Failed to load config from ${CONFIG_PATH}:`, error.message); | |
| process.exit(1); | |
| } | |
| } | |
| const config = loadConfig(); | |
| function createMcpServer() { | |
| const server = new Server( | |
| { | |
| name: "mcponly-server", | |
| version: "1.0.0", | |
| }, | |
| { | |
| capabilities: { | |
| tools: {}, | |
| }, | |
| }, | |
| ); | |
| server.setRequestHandler(ListToolsRequestSchema, async () => ({ | |
| tools: [...routerTools, ...curateTools, ...vectorTools], | |
| })); | |
| server.setRequestHandler(CallToolRequestSchema, async (request) => { | |
| const { name, arguments: args = {} } = request.params; | |
| const routerResult = await handleRouterTool(name, args, config); | |
| if (routerResult) return routerResult; | |
| const curateResult = await handleCurateTool(name, args, config); | |
| if (curateResult) return curateResult; | |
| const vectorResult = await handleVectorTool(name, args); | |
| if (vectorResult) return vectorResult; | |
| return { | |
| content: [{ type: "text", text: `Unknown tool: ${name}` }], | |
| isError: true, | |
| }; | |
| }); | |
| return server; | |
| } | |
| function sendJson(res, statusCode, payload) { | |
| res.writeHead(statusCode, { "Content-Type": "application/json" }); | |
| res.end(JSON.stringify(payload)); | |
| } | |
| function readBody(req) { | |
| return new Promise((resolve, reject) => { | |
| const chunks = []; | |
| req.on("data", (chunk) => chunks.push(chunk)); | |
| req.on("end", () => { | |
| if (chunks.length === 0) { | |
| resolve(undefined); | |
| return; | |
| } | |
| const text = Buffer.concat(chunks).toString("utf8"); | |
| try { | |
| resolve(JSON.parse(text)); | |
| } catch (error) { | |
| reject(new Error("Invalid JSON body")); | |
| } | |
| }); | |
| req.on("error", reject); | |
| }); | |
| } | |
| async function main() { | |
| const transports = new Map(); | |
| const httpServer = http.createServer(async (req, res) => { | |
| if (!req.url) { | |
| sendJson(res, 400, { | |
| jsonrpc: "2.0", | |
| error: { code: -32600, message: "Missing request URL" }, | |
| id: null, | |
| }); | |
| return; | |
| } | |
| const hostHeader = req.headers.host || `${HOST}:${PORT}`; | |
| const url = new URL(req.url, `http://${hostHeader}`); | |
| if (req.method === "GET" && url.pathname === "/health") { | |
| sendJson(res, 200, { status: "ok" }); | |
| return; | |
| } | |
| if (req.method === "GET" && url.pathname === "/sse") { | |
| const transport = new SSEServerTransport("/messages", res); | |
| transports.set(transport.sessionId, transport); | |
| transport.onclose = () => { | |
| transports.delete(transport.sessionId); | |
| }; | |
| res.on("close", () => { | |
| transports.delete(transport.sessionId); | |
| }); | |
| await createMcpServer().connect(transport); | |
| return; | |
| } | |
| if (req.method === "POST" && url.pathname === "/messages") { | |
| const sessionId = url.searchParams.get("sessionId"); | |
| if (!sessionId) { | |
| sendJson(res, 400, { | |
| jsonrpc: "2.0", | |
| error: { code: -32600, message: "Missing sessionId query parameter" }, | |
| id: null, | |
| }); | |
| return; | |
| } | |
| const transport = transports.get(sessionId); | |
| if (!transport) { | |
| sendJson(res, 404, { | |
| jsonrpc: "2.0", | |
| error: { code: -32000, message: "Session not found" }, | |
| id: null, | |
| }); | |
| return; | |
| } | |
| const body = await readBody(req); | |
| await transport.handlePostMessage(req, res, body); | |
| return; | |
| } | |
| sendJson(res, 404, { | |
| jsonrpc: "2.0", | |
| error: { code: -32601, message: "Not found" }, | |
| id: null, | |
| }); | |
| }); | |
| httpServer.listen(PORT, HOST, () => { | |
| console.log(`MCP SSE server listening on http://${HOST}:${PORT}`); | |
| console.log(`SSE endpoint: http://${HOST}:${PORT}/sse`); | |
| console.log(`POST endpoint: http://${HOST}:${PORT}/messages`); | |
| }); | |
| process.on("SIGINT", () => { | |
| httpServer.close(() => process.exit(0)); | |
| }); | |
| } | |
| main().catch((error) => { | |
| console.error("MCP server failed to start:", error); | |
| process.exit(1); | |
| }); | |