Files
mcpedia/apps/mcp/src/http.ts
T

44 lines
1.7 KiB
TypeScript
Raw Normal View History

import { createServer, type IncomingMessage, type ServerResponse } from "node:http";
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
import { createMcpServer } from "./index";
// Phase 3 follow-up: serve the MCPedia MCP server over Streamable HTTP
// (MCP 2025-03-26 transport) so remote clients can use its tools/resources
// without spawning a stdio subprocess. Stateless mode (sessionIdGenerator
// undefined): one McpServer + transport per request, no session affinity, no
// shared-transport connect race, no session-map memory leak. Re-registering
// 6 tools + 4 resources per request is negligible for a KB-sized corpus.
const PORT = Number(process.env.MCP_PORT ?? 4021);
const PATH = "/mcp";
const CORS: Record<string, string> = {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET, POST, DELETE, OPTIONS",
"Access-Control-Allow-Headers":
"Content-Type, Accept, Authorization, MCP-Protocol-Version, mcp-session-id",
};
const httpServer = createServer(async (req: IncomingMessage, res: ServerResponse) => {
for (const [k, v] of Object.entries(CORS)) res.setHeader(k, v);
if (req.method === "OPTIONS") {
res.writeHead(204).end();
return;
}
if ((req.url ?? "").split("?")[0] !== PATH) {
res.writeHead(404).end("Not found");
return;
}
// Stateless: fresh server + transport per request.
const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: undefined });
const server = createMcpServer();
await server.connect(transport);
await transport.handleRequest(req, res);
});
httpServer.listen(PORT, () => {
console.log(`MCPedia MCP server (Streamable HTTP) listening on http://localhost:${PORT}/mcp`);
});