Skip to main content
Glama
streamableHttp.js6.33 kB
"use strict"; /** * Node.js HTTP Streamable HTTP Server Transport * * This is a thin wrapper around `WebStandardStreamableHTTPServerTransport` that provides * compatibility with Node.js HTTP server (IncomingMessage/ServerResponse). * * For web-standard environments (Cloudflare Workers, Deno, Bun), use `WebStandardStreamableHTTPServerTransport` directly. */ Object.defineProperty(exports, "__esModule", { value: true }); exports.StreamableHTTPServerTransport = void 0; const node_server_1 = require("@hono/node-server"); const webStandardStreamableHttp_js_1 = require("./webStandardStreamableHttp.js"); /** * Server transport for Streamable HTTP: this implements the MCP Streamable HTTP transport specification. * It supports both SSE streaming and direct HTTP responses. * * This is a wrapper around `WebStandardStreamableHTTPServerTransport` that provides Node.js HTTP compatibility. * It uses the `@hono/node-server` library to convert between Node.js HTTP and Web Standard APIs. * * Usage example: * * ```typescript * // Stateful mode - server sets the session ID * const statefulTransport = new StreamableHTTPServerTransport({ * sessionIdGenerator: () => randomUUID(), * }); * * // Stateless mode - explicitly set session ID to undefined * const statelessTransport = new StreamableHTTPServerTransport({ * sessionIdGenerator: undefined, * }); * * // Using with pre-parsed request body * app.post('/mcp', (req, res) => { * transport.handleRequest(req, res, req.body); * }); * ``` * * In stateful mode: * - Session ID is generated and included in response headers * - Session ID is always included in initialization responses * - Requests with invalid session IDs are rejected with 404 Not Found * - Non-initialization requests without a session ID are rejected with 400 Bad Request * - State is maintained in-memory (connections, message history) * * In stateless mode: * - No Session ID is included in any responses * - No session validation is performed */ class StreamableHTTPServerTransport { constructor(options = {}) { // Store auth and parsedBody per request for passing through to handleRequest this._requestContext = new WeakMap(); this._webStandardTransport = new webStandardStreamableHttp_js_1.WebStandardStreamableHTTPServerTransport(options); // Create a request listener that wraps the web standard transport // getRequestListener converts Node.js HTTP to Web Standard and properly handles SSE streaming this._requestListener = (0, node_server_1.getRequestListener)(async (webRequest) => { // Get context if available (set during handleRequest) const context = this._requestContext.get(webRequest); return this._webStandardTransport.handleRequest(webRequest, { authInfo: context?.authInfo, parsedBody: context?.parsedBody }); }); } /** * Gets the session ID for this transport instance. */ get sessionId() { return this._webStandardTransport.sessionId; } /** * Sets callback for when the transport is closed. */ set onclose(handler) { this._webStandardTransport.onclose = handler; } get onclose() { return this._webStandardTransport.onclose; } /** * Sets callback for transport errors. */ set onerror(handler) { this._webStandardTransport.onerror = handler; } get onerror() { return this._webStandardTransport.onerror; } /** * Sets callback for incoming messages. */ set onmessage(handler) { this._webStandardTransport.onmessage = handler; } get onmessage() { return this._webStandardTransport.onmessage; } /** * Starts the transport. This is required by the Transport interface but is a no-op * for the Streamable HTTP transport as connections are managed per-request. */ async start() { return this._webStandardTransport.start(); } /** * Closes the transport and all active connections. */ async close() { return this._webStandardTransport.close(); } /** * Sends a JSON-RPC message through the transport. */ async send(message, options) { return this._webStandardTransport.send(message, options); } /** * Handles an incoming HTTP request, whether GET or POST. * * This method converts Node.js HTTP objects to Web Standard Request/Response * and delegates to the underlying WebStandardStreamableHTTPServerTransport. * * @param req - Node.js IncomingMessage, optionally with auth property from middleware * @param res - Node.js ServerResponse * @param parsedBody - Optional pre-parsed body from body-parser middleware */ async handleRequest(req, res, parsedBody) { // Store context for this request to pass through auth and parsedBody // We need to intercept the request creation to attach this context const authInfo = req.auth; // Create a custom handler that includes our context const handler = (0, node_server_1.getRequestListener)(async (webRequest) => { return this._webStandardTransport.handleRequest(webRequest, { authInfo, parsedBody }); }); // Delegate to the request listener which handles all the Node.js <-> Web Standard conversion // including proper SSE streaming support await handler(req, res); } /** * Close an SSE stream for a specific request, triggering client reconnection. * Use this to implement polling behavior during long-running operations - * client will reconnect after the retry interval specified in the priming event. */ closeSSEStream(requestId) { this._webStandardTransport.closeSSEStream(requestId); } /** * Close the standalone GET SSE stream, triggering client reconnection. * Use this to implement polling behavior for server-initiated notifications. */ closeStandaloneSSEStream() { this._webStandardTransport.closeStandaloneSSEStream(); } } exports.StreamableHTTPServerTransport = StreamableHTTPServerTransport; //# sourceMappingURL=streamableHttp.js.map

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/Valerio357/bet-mcp'

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