| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165 |
- "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
- // overrideGlobalObjects: false prevents Hono from overwriting global Response, which would
- // break frameworks like Next.js whose response classes extend the native Response
- 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
- });
- }, { overrideGlobalObjects: false });
- }
- /**
- * 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
- // overrideGlobalObjects: false prevents Hono from overwriting global Response, which would
- // break frameworks like Next.js whose response classes extend the native Response
- const handler = (0, node_server_1.getRequestListener)(async (webRequest) => {
- return this._webStandardTransport.handleRequest(webRequest, {
- authInfo,
- parsedBody
- });
- }, { overrideGlobalObjects: false });
- // 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
|