( createServer: () => Server, endpoint = "/mcp", port = 1122, host = "localhost", )
| 5 | import { logger } from "../utils/logger"; |
| 6 | |
| 7 | export const startHTTPStreamableServer = async ( |
| 8 | createServer: () => Server, |
| 9 | endpoint = "/mcp", |
| 10 | port = 1122, |
| 11 | host = "localhost", |
| 12 | ): Promise<void> => { |
| 13 | const app = express(); |
| 14 | app.use(express.json()); |
| 15 | app.use(cors({ origin: "*", exposedHeaders: ["Mcp-Session-Id"] })); |
| 16 | |
| 17 | app.post(endpoint, async (req: Request, res: Response) => { |
| 18 | // In stateless mode, create a new transport for each request to prevent |
| 19 | // request ID collisions. Different clients may use the same JSON-RPC request IDs, |
| 20 | // which would cause responses to be routed to the wrong HTTP connections if |
| 21 | // the transport state is shared. |
| 22 | try { |
| 23 | const server = createServer(); |
| 24 | const transport = new StreamableHTTPServerTransport({ |
| 25 | sessionIdGenerator: undefined, |
| 26 | enableJsonResponse: true, |
| 27 | }); |
| 28 | |
| 29 | res.on("close", () => { |
| 30 | transport.close(); |
| 31 | logger.info("HTTP Streamable Server response closed"); |
| 32 | }); |
| 33 | |
| 34 | await server.connect(transport); |
| 35 | await transport.handleRequest(req, res, req.body); |
| 36 | logger.info("HTTP Streamable Server response connected"); |
| 37 | } catch (e) { |
| 38 | logger.error("HTTP Streamable Server response error", e); |
| 39 | if (!res.headersSent) { |
| 40 | res.status(500).json({ |
| 41 | jsonrpc: "2.0", |
| 42 | error: { code: -32603, message: "Internal server error" }, |
| 43 | id: null, |
| 44 | }); |
| 45 | } |
| 46 | } |
| 47 | }); |
| 48 | |
| 49 | app.listen(port, host, () => { |
| 50 | logger.success( |
| 51 | `Streamable HTTP Server listening on http://${host}:${port}${endpoint}`, |
| 52 | ); |
| 53 | }); |
| 54 | }; |
no test coverage detected