const require_chunk = require('./chunk-Bnu9O96Y.cjs'); const require_mcp = require('./mcp-BumlNux0.cjs'); const require_src = require('./src-BhnGYybN.cjs'); let _modelcontextprotocol_server__shims = require("@modelcontextprotocol/server/_shims"); let _modelcontextprotocol_core_internal = require("@modelcontextprotocol/core/internal"); //#region src/server/perRequestTransport.ts /** * The per-request micro-transport: a real, connected `Transport` whose whole * lifetime is one HTTP exchange. See the module documentation for the * response shapes it produces. */ var PerRequestHTTPServerTransport = class { onclose; onerror; onmessage; _classification; _responseMode; _started = false; _used = false; _closed = false; _terminalDelivered = false; /** * `true` only while the inbound message is being delivered synchronously * to the connected protocol layer. The pre-handler gates (the era * registry gate, the edge→instance handoff check, the missing-handler * rejection) answer inside this window; request handlers always run * after it (the protocol layer defers them to a microtask). An error * sent inside the window is therefore ladder-originated, and an error * sent after it is handler-produced. */ _dispatchWindowOpen = false; _requestId; _deferredResponse; _sse; _abortCleanup; _keepAliveMs; constructor(options) { this._classification = options.classification; this._responseMode = options.responseMode ?? "auto"; this._keepAliveMs = options.keepAliveMs ?? require_mcp.DEFAULT_SSE_KEEP_ALIVE_MS; } async start() { if (this._started) throw new Error("PerRequestHTTPServerTransport is already started"); this._started = true; } /** * Serves the single exchange: delivers the classified message to the * connected server instance and resolves with the HTTP response. * * Throws when called a second time (the transport is strictly * single-use), or before a server has been connected to the transport. * The returned promise rejects with a connection-closed error when the * transport is closed before a response was produced (for example because * the client disconnected). */ async handleMessage(message, extra) { if (this._used) throw new Error("PerRequestHTTPServerTransport serves exactly one exchange; construct a new transport per request"); if (!this._started || this.onmessage === void 0) throw new Error("PerRequestHTTPServerTransport is not connected: connect a server to this transport before handling a message"); if (this._closed) throw new Error("PerRequestHTTPServerTransport is closed"); this._used = true; const signal = extra?.request?.signal; if (signal?.aborted) { await this.close(); throw new require_src.SdkError(require_src.SdkErrorCode.ConnectionClosed, "The request was aborted before it could be handled"); } const messageExtra = { classification: this._classification, ...extra?.request !== void 0 && { request: extra.request }, ...extra?.authInfo !== void 0 && { authInfo: extra.authInfo } }; if (require_src.isJSONRPCRequest(message)) { this._requestId = message.id; let resolve; let reject; const promise = new Promise((promiseResolve, promiseReject) => { resolve = promiseResolve; reject = promiseReject; }); this._deferredResponse = { promise, resolve, reject, settled: false }; if (signal !== void 0) { const onAbort = () => void this.close(); signal.addEventListener("abort", onAbort, { once: true }); this._abortCleanup = () => signal.removeEventListener("abort", onAbort); } this._dispatchWindowOpen = true; try { this.onmessage(message, messageExtra); } finally { this._dispatchWindowOpen = false; } if (this._responseMode === "sse" && !this._closed && !this._deferredResponse.settled) this.upgradeToSse(); return promise; } this.onmessage(message, messageExtra); return new Response(null, { status: 202 }); } async send(message, options) { if (this._closed) return; const isResponse = require_src.isJSONRPCResultResponse(message) || require_src.isJSONRPCErrorResponse(message); const relatedId = isResponse ? message.id : options?.relatedRequestId; if (this._requestId === void 0 || relatedId === void 0 || relatedId !== this._requestId) { if (isResponse) this.onerror?.(/* @__PURE__ */ new Error(`Received a response for an unknown request id: ${String(message.id)}`)); return; } if (isResponse) { if (this._terminalDelivered) return; this._terminalDelivered = true; const errorCode = require_src.isJSONRPCErrorResponse(message) ? message.error.code : void 0; const ladderStatus = errorCode !== void 0 && (this._dispatchWindowOpen || errorCode === require_src.ProtocolErrorCode.MissingRequiredClientCapability) ? require_src.LADDER_ERROR_HTTP_STATUS[errorCode] : void 0; if (ladderStatus !== void 0 && this._sse === void 0) { this.settleResponse(Response.json(message, { status: ladderStatus, headers: { "Content-Type": "application/json" } })); queueMicrotask(() => void this.close()); return; } if (this._sse !== void 0 || this._responseMode === "sse") { if (this._sse === void 0) this.upgradeToSse(); this.writeMessageFrame(message); this.finalizeStream(); return; } this.settleResponse(Response.json(message, { status: 200, headers: { "Content-Type": "application/json" } })); queueMicrotask(() => void this.close()); return; } if (this._responseMode === "json") return; if (this._sse === void 0) this.upgradeToSse(); this.writeMessageFrame(message); } /** * Writes an SSE comment frame (a keep-alive heartbeat). Dropped when the * exchange is not currently streaming. */ writeCommentFrame(comment) { if (this._closed || this._sse === void 0 || this._sse.closed) return; const frame = comment.split("\n").map((line) => `: ${line}`).join("\n"); this.writeFrame(`${frame}\n\n`); } async close() { if (this._closed) return; this._closed = true; this._abortCleanup?.(); this._abortCleanup = void 0; if (this._sse?.keepAliveTimer !== void 0) clearInterval(this._sse.keepAliveTimer); if (this._sse !== void 0 && !this._sse.closed) { this._sse.closed = true; try { this._sse.controller.close(); } catch {} } if (this._deferredResponse !== void 0 && !this._deferredResponse.settled) { this._deferredResponse.settled = true; this._deferredResponse.reject(new require_src.SdkError(require_src.SdkErrorCode.ConnectionClosed, "Connection closed before a response was produced")); } this.onclose?.(); } settleResponse(response) { if (this._deferredResponse === void 0 || this._deferredResponse.settled) return; this._deferredResponse.settled = true; this._deferredResponse.resolve(response); } upgradeToSse() { let controller; const readable = new ReadableStream({ start: (streamController) => { controller = streamController; }, cancel: () => { this.close(); } }); this._sse = { controller, encoder: new TextEncoder(), closed: false }; this._sse.keepAliveTimer = require_mcp.armSseKeepAlive(this._keepAliveMs, () => this.writeCommentFrame("keepalive")); this.settleResponse(new Response(readable, { status: 200, headers: { "Content-Type": "text/event-stream", "Cache-Control": "no-cache, no-transform", Connection: "keep-alive", "X-Accel-Buffering": "no" } })); } finalizeStream() { if (this._sse?.keepAliveTimer !== void 0) clearInterval(this._sse.keepAliveTimer); if (this._sse !== void 0 && !this._sse.closed) { this._sse.closed = true; try { this._sse.controller.close(); } catch {} } queueMicrotask(() => void this.close()); } writeMessageFrame(message) { this.writeFrame(`event: message\ndata: ${JSON.stringify(message)}\n\n`); } writeFrame(frame) { if (this._sse === void 0 || this._sse.closed) return; try { this._sse.controller.enqueue(this._sse.encoder.encode(frame)); } catch (error) { this.onerror?.(/* @__PURE__ */ new Error(`Failed to write to the response stream: ${error}`)); } } }; //#endregion //#region src/server/invoke.ts /** * Serves one classified inbound message on the given server instance and * returns the HTTP response for the exchange. * * The instance is connected to a fresh single-exchange transport, the message * is injected through the normal transport message path, and whatever the * dispatch layer produces (the handler result, a protocol-level rejection, or * streamed related messages followed by the result) is captured as the * returned `Response`. For request exchanges, teardown rides the transport's * close chain once the terminal response has been delivered; notification * exchanges resolve with the 202 response immediately and do NOT run the * close chain — the transport stays connected until the caller closes it or * drops the per-request instance, which is the caller's choice either way. */ async function invoke(server, message, ctx) { const transport = new PerRequestHTTPServerTransport({ classification: ctx.classification, ...ctx.responseMode !== void 0 && { responseMode: ctx.responseMode }, ...ctx.keepAliveMs !== void 0 && { keepAliveMs: ctx.keepAliveMs } }); await server.connect(transport); return transport.handleMessage(message, { ...ctx.request !== void 0 && { request: ctx.request }, ...ctx.authInfo !== void 0 && { authInfo: ctx.authInfo } }); } //#endregion //#region src/server/requestBody.ts /** Default upper bound, in bytes, on a request body read by the HTTP entry points (4 MiB). */ const DEFAULT_MAX_REQUEST_BODY_SIZE = 4 * 1024 * 1024; /** Upper bound on the number of messages accepted in one JSON-RPC batch array. */ const MAX_BATCH_SIZE = 100; /** The message answered with 413 for a request body over `maxBytes`. */ function requestBodyTooLargeMessage(maxBytes) { return `Payload Too Large: Request body must not exceed ${maxBytes} bytes`; } /** * Resolves a `maxRequestBodySize` option to the bound to apply: the default when * omitted, otherwise the value itself, which must be a positive finite number of * bytes (a `RangeError` is thrown at configuration time for anything else). */ function resolveMaxRequestBodySize(value) { if (value === void 0) return DEFAULT_MAX_REQUEST_BODY_SIZE; if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) throw new RangeError(`maxRequestBodySize must be a positive number of bytes, got ${String(value)}`); return value; } /** * Reads a request body as text, up to `maxBytes` (default * {@linkcode DEFAULT_MAX_REQUEST_BODY_SIZE}). A declared `Content-Length` over the * limit is refused without reading anything; otherwise the read stops as soon as * more than the limit has arrived. Stream failures propagate. */ async function readRequestBody(request, maxBytes = DEFAULT_MAX_REQUEST_BODY_SIZE) { if (Number(request.headers.get("content-length")) > maxBytes) return { tooLarge: true }; if (request.body === null) return { tooLarge: false, text: "" }; const reader = request.body.getReader(); const decoder = new TextDecoder(); let received = 0; let text = ""; try { for (;;) { const { done, value } = await reader.read(); if (done) break; received += value.byteLength; if (received > maxBytes) return { tooLarge: true }; text += decoder.decode(value, { stream: true }); } } finally { reader.releaseLock(); } return { tooLarge: false, text: text + decoder.decode() }; } //#endregion //#region src/server/streamableHttp.ts /** * Server transport for Web Standards Streamable HTTP: this implements the MCP Streamable HTTP transport specification * using Web Standard APIs (`Request`, `Response`, `ReadableStream`). * * This transport works on any runtime that supports Web Standards: Node.js 18+, Cloudflare Workers, Deno, Bun, etc. * * 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 * * @example Stateful setup * ```ts source="./streamableHttp.examples.ts#WebStandardStreamableHTTPServerTransport_stateful" * const server = new McpServer({ name: 'my-server', version: '1.0.0' }); * * const transport = new WebStandardStreamableHTTPServerTransport({ * sessionIdGenerator: () => crypto.randomUUID() * }); * * await server.connect(transport); * ``` * * @example Stateless setup * ```ts source="./streamableHttp.examples.ts#WebStandardStreamableHTTPServerTransport_stateless" * const transport = new WebStandardStreamableHTTPServerTransport({ * sessionIdGenerator: undefined * }); * ``` * * @example Hono.js * ```ts source="./streamableHttp.examples.ts#WebStandardStreamableHTTPServerTransport_hono" * app.all('/mcp', async c => { * // Stateless example: create a server and a transport per request. * const server = new McpServer({ name: 'my-server', version: '1.0.0' }); * const transport = new WebStandardStreamableHTTPServerTransport({ sessionIdGenerator: undefined }); * await server.connect(transport); * return transport.handleRequest(c.req.raw); * }); * ``` * * @example Cloudflare Workers * ```ts source="./streamableHttp.examples.ts#WebStandardStreamableHTTPServerTransport_workers" * const worker = { * async fetch(request: Request): Promise { * // Stateless example: create a server and a transport per request. * const server = new McpServer({ name: 'my-server', version: '1.0.0' }); * const transport = new WebStandardStreamableHTTPServerTransport({ sessionIdGenerator: undefined }); * await server.connect(transport); * return transport.handleRequest(request); * } * }; * ``` */ var WebStandardStreamableHTTPServerTransport = class { sessionIdGenerator; _started = false; _hasHandledRequest = false; _closed = false; _streamMapping = /* @__PURE__ */ new Map(); _requestToStreamMapping = /* @__PURE__ */ new Map(); _requestResponseMap = /* @__PURE__ */ new Map(); _initialized = false; _enableJsonResponse = false; _standaloneSseStreamId = "_GET_stream"; _eventStore; _onsessioninitialized; _onsessionclosed; _allowedHosts; _allowedOrigins; _enableDnsRebindingProtection; _retryInterval; _supportedProtocolVersions; _keepAliveMs; _maxRequestBodySize; _scopeChallengeResolver; sessionId; onclose; onerror; onmessage; constructor(options = {}) { this.sessionIdGenerator = options.sessionIdGenerator; this._enableJsonResponse = options.enableJsonResponse ?? false; this._eventStore = options.eventStore; this._onsessioninitialized = options.onsessioninitialized; this._onsessionclosed = options.onsessionclosed; this._allowedHosts = options.allowedHosts; this._allowedOrigins = options.allowedOrigins; this._enableDnsRebindingProtection = options.enableDnsRebindingProtection ?? false; this._retryInterval = options.retryInterval; this._supportedProtocolVersions = options.supportedProtocolVersions ?? _modelcontextprotocol_core_internal.SUPPORTED_PROTOCOL_VERSIONS; this._keepAliveMs = options.keepAliveMs ?? require_mcp.DEFAULT_SSE_KEEP_ALIVE_MS; this._maxRequestBodySize = resolveMaxRequestBodySize(options.maxRequestBodySize); } startKeepAlive(controller, encoder) { if (this._closed) return void 0; const timer = require_mcp.armSseKeepAlive(this._keepAliveMs, () => { try { controller.enqueue(encoder.encode(": keepalive\n\n")); } catch { if (timer !== void 0) clearInterval(timer); } }); return timer; } /** Sets the scope challenge resolver for parsed JSON-RPC requests. */ setScopeChallengeResolver(resolver) { this._scopeChallengeResolver = resolver; } /** * Starts the transport. This is required by the {@linkcode Transport} interface but is a no-op * for the Streamable HTTP transport as connections are managed per-request. */ async start() { if (this._started) throw new Error("Transport already started"); this._started = true; } /** * Sets the supported protocol versions for header validation. * Called by the server during {@linkcode server/server.Server.connect | connect()} to pass its supported versions. */ setSupportedProtocolVersions(versions) { this._supportedProtocolVersions = versions; } /** * Helper to create a JSON error response */ createJsonErrorResponse(status, code, message, options) { const error = { code, message }; if (options?.data !== void 0) error.data = options.data; return Response.json({ jsonrpc: "2.0", error, id: null }, { status, headers: { "Content-Type": "application/json", ...options?.headers } }); } async _checkScopeChallenge(messages, authInfo) { if (!this._scopeChallengeResolver) return; const challenge = await require_mcp.findScopeChallenge(messages.filter((message) => require_src.isJSONRPCRequest(message)), authInfo, this._scopeChallengeResolver); return challenge === void 0 ? void 0 : require_mcp.createScopeChallengeResponse(challenge, require_mcp.scopeChallengeResourceMetadataUrl(authInfo)); } /** * Validates request headers for DNS rebinding protection. * @returns Error response if validation fails, `undefined` if validation passes. */ validateRequestHeaders(req) { if (!this._enableDnsRebindingProtection) return; if (this._allowedHosts && this._allowedHosts.length > 0) { const hostHeader = req.headers.get("host"); if (!hostHeader || !this._allowedHosts.includes(hostHeader)) { const error = `Invalid Host header: ${hostHeader}`; this.onerror?.(new Error(error)); return this.createJsonErrorResponse(403, -32e3, error); } } if (this._allowedOrigins && this._allowedOrigins.length > 0) { const originHeader = req.headers.get("origin"); if (originHeader && !this._allowedOrigins.includes(originHeader)) { const error = `Invalid Origin header: ${originHeader}`; this.onerror?.(new Error(error)); return this.createJsonErrorResponse(403, -32e3, error); } } } /** * Handles an incoming HTTP request, whether `GET`, `POST`, or `DELETE` * Returns a `Response` object (Web Standard) */ async handleRequest(req, options) { if (this._closed) return this.createJsonErrorResponse(404, -32001, "Session not found"); if (!this.sessionIdGenerator && this._hasHandledRequest) throw new Error("Stateless transport cannot be reused across requests. Create a new transport per request."); this._hasHandledRequest = true; const validationError = this.validateRequestHeaders(req); if (validationError) return validationError; switch (req.method) { case "POST": return this.handlePostRequest(req, options); case "GET": return this.handleGetRequest(req); case "DELETE": return this.handleDeleteRequest(req); default: return this.handleUnsupportedRequest(); } } /** * Returns true if the client's protocol version supports empty SSE data in * priming events (the fix shipped with protocol version `2025-11-25`). * * The version is checked for membership in this transport instance's * supported protocol versions rather than with an open-ended * `>= '2025-11-25'` comparison: the value may come from an `initialize` * request body, which (unlike the `MCP-Protocol-Version` header) is not * validated against `supportedProtocolVersions` before reaching this * check. An unknown future version string must not silently enable * behavior reserved for versions this transport actually supports. */ supportsEmptySSEData(protocolVersion) { return this._supportedProtocolVersions.includes(protocolVersion) && protocolVersion >= "2025-11-25"; } /** * Writes a priming event to establish resumption capability. * Only sends if `eventStore` is configured (opt-in for resumability) and * the client's protocol version supports empty SSE data (a supported * version that is >= `2025-11-25`). */ async writePrimingEvent(controller, encoder, streamId, protocolVersion) { if (!this._eventStore) return; if (!this.supportsEmptySSEData(protocolVersion)) return; const primingEventId = await this._eventStore.storeEvent(streamId, {}); let primingEvent = `id: ${primingEventId}\ndata: \n\n`; if (this._retryInterval !== void 0) primingEvent = `id: ${primingEventId}\nretry: ${this._retryInterval}\ndata: \n\n`; controller.enqueue(encoder.encode(primingEvent)); } /** * Handles `GET` requests for SSE stream */ async handleGetRequest(req) { if (!req.headers.get("accept")?.includes("text/event-stream")) { this.onerror?.(/* @__PURE__ */ new Error("Not Acceptable: Client must accept text/event-stream")); return this.createJsonErrorResponse(406, -32e3, "Not Acceptable: Client must accept text/event-stream"); } const sessionError = this.validateSession(req); if (sessionError) return sessionError; const protocolError = this.validateProtocolVersion(req); if (protocolError) return protocolError; if (this._eventStore) { const lastEventId = req.headers.get("last-event-id"); if (lastEventId) return this.replayEvents(lastEventId); } if (this._streamMapping.get(this._standaloneSseStreamId) !== void 0) { this.onerror?.(/* @__PURE__ */ new Error("Conflict: Only one SSE stream is allowed per session")); return this.createJsonErrorResponse(409, -32e3, "Conflict: Only one SSE stream is allowed per session"); } const encoder = new TextEncoder(); let streamController; let keepAliveTimer; const readable = new ReadableStream({ start: (controller) => { streamController = controller; }, cancel: () => { if (keepAliveTimer !== void 0) clearInterval(keepAliveTimer); if (this._streamMapping.get(this._standaloneSseStreamId)?.controller === streamController) this._streamMapping.delete(this._standaloneSseStreamId); } }); const headers = { "Content-Type": "text/event-stream", "Cache-Control": "no-cache, no-transform", Connection: "keep-alive", "X-Accel-Buffering": "no" }; if (this.sessionId !== void 0) headers["mcp-session-id"] = this.sessionId; this._streamMapping.set(this._standaloneSseStreamId, { controller: streamController, encoder, cleanup: () => { if (keepAliveTimer !== void 0) clearInterval(keepAliveTimer); this._streamMapping.delete(this._standaloneSseStreamId); try { streamController.close(); } catch {} } }); keepAliveTimer = this.startKeepAlive(streamController, encoder); return new Response(readable, { headers }); } /** * Replays events that would have been sent after the specified event ID * Only used when resumability is enabled */ async replayEvents(lastEventId) { if (!this._eventStore) { this.onerror?.(/* @__PURE__ */ new Error("Event store not configured")); return this.createJsonErrorResponse(400, -32e3, "Event store not configured"); } try { let streamId; if (this._eventStore.getStreamIdForEventId) { streamId = await this._eventStore.getStreamIdForEventId(lastEventId); if (!streamId) { this.onerror?.(/* @__PURE__ */ new Error("Invalid event ID format")); return this.createJsonErrorResponse(400, -32e3, "Invalid event ID format"); } if (this._streamMapping.get(streamId) !== void 0) { this.onerror?.(/* @__PURE__ */ new Error("Conflict: Stream already has an active connection")); return this.createJsonErrorResponse(409, -32e3, "Conflict: Stream already has an active connection"); } } const headers = { "Content-Type": "text/event-stream", "Cache-Control": "no-cache, no-transform", Connection: "keep-alive", "X-Accel-Buffering": "no" }; if (this.sessionId !== void 0) headers["mcp-session-id"] = this.sessionId; const encoder = new TextEncoder(); let streamController; let keepAliveTimer; let cancelled = false; let replayedStreamId; const readable = new ReadableStream({ start: (controller) => { streamController = controller; }, cancel: () => { cancelled = true; if (keepAliveTimer !== void 0) clearInterval(keepAliveTimer); if (replayedStreamId !== void 0 && this._streamMapping.get(replayedStreamId)?.controller === streamController) this._streamMapping.delete(replayedStreamId); } }); const replayedEventIds = /* @__PURE__ */ new Set(); replayedStreamId = await this._eventStore.replayEventsAfter(lastEventId, { send: async (eventId, message) => { replayedEventIds.add(eventId); if (!this.writeSSEEvent(streamController, encoder, message, eventId)) try { streamController.close(); } catch {} } }); if (this._closed || cancelled) { try { streamController.close(); } catch {} return this.createJsonErrorResponse(404, -32001, "Session not found"); } this._streamMapping.get(replayedStreamId)?.cleanup(); this._streamMapping.set(replayedStreamId, { controller: streamController, encoder, replayedEventIds, cleanup: () => { if (keepAliveTimer !== void 0) clearInterval(keepAliveTimer); this._streamMapping.delete(replayedStreamId); try { streamController.close(); } catch {} } }); if (replayedStreamId !== this._standaloneSseStreamId) { if (![...this._requestToStreamMapping.values()].includes(replayedStreamId)) { this._streamMapping.delete(replayedStreamId); try { streamController.close(); } catch {} } } if (this._streamMapping.get(replayedStreamId)?.controller === streamController) keepAliveTimer = this.startKeepAlive(streamController, encoder); return new Response(readable, { headers }); } catch (error) { this.onerror?.(error); return this.createJsonErrorResponse(500, -32e3, "Error replaying events"); } } /** * Writes an event to an SSE stream via controller with proper formatting */ writeSSEEvent(controller, encoder, message, eventId) { try { let eventData = `event: message\n`; if (eventId) eventData += `id: ${eventId}\n`; eventData += `data: ${JSON.stringify(message)}\n\n`; controller.enqueue(encoder.encode(eventData)); return true; } catch (error) { this.onerror?.(error); return false; } } /** * Handles unsupported requests (`PUT`, `PATCH`, etc.) */ handleUnsupportedRequest() { this.onerror?.(/* @__PURE__ */ new Error("Method not allowed.")); return Response.json({ jsonrpc: "2.0", error: { code: -32e3, message: "Method not allowed." }, id: null }, { status: 405, headers: { Allow: "GET, POST, DELETE", "Content-Type": "application/json" } }); } /** * Handles `POST` requests containing JSON-RPC messages */ async handlePostRequest(req, options) { try { const acceptHeader = req.headers.get("accept"); if (!acceptHeader?.includes("application/json") || !acceptHeader.includes("text/event-stream")) { this.onerror?.(/* @__PURE__ */ new Error("Not Acceptable: Client must accept both application/json and text/event-stream")); return this.createJsonErrorResponse(406, -32e3, "Not Acceptable: Client must accept both application/json and text/event-stream"); } if (!require_src.isJsonContentType(req.headers.get("content-type"))) { this.onerror?.(/* @__PURE__ */ new Error("Unsupported Media Type: Content-Type must be application/json")); return this.createJsonErrorResponse(415, -32e3, "Unsupported Media Type: Content-Type must be application/json"); } const request = req; let rawMessage; if (options?.parsedBody === void 0) try { const body = await readRequestBody(req, this._maxRequestBodySize); if (body.tooLarge) { const message = requestBodyTooLargeMessage(this._maxRequestBodySize); this.onerror?.(new Error(message)); return this.createJsonErrorResponse(413, -32e3, message); } rawMessage = JSON.parse(body.text); } catch (error) { this.onerror?.(error); return this.createJsonErrorResponse(400, -32700, "Parse error: Invalid JSON"); } else rawMessage = options.parsedBody; if (Array.isArray(rawMessage) && rawMessage.length > MAX_BATCH_SIZE) { this.onerror?.(/* @__PURE__ */ new Error(`Invalid Request: Batch must not exceed ${MAX_BATCH_SIZE} messages`)); return this.createJsonErrorResponse(400, -32600, `Invalid Request: Batch must not exceed ${MAX_BATCH_SIZE} messages`); } let messages; try { messages = Array.isArray(rawMessage) ? rawMessage.map((msg) => _modelcontextprotocol_core_internal.JSONRPCMessageSchema.parse(msg)) : [_modelcontextprotocol_core_internal.JSONRPCMessageSchema.parse(rawMessage)]; } catch (error) { this.onerror?.(error); return this.createJsonErrorResponse(400, -32700, "Parse error: Invalid JSON-RPC message"); } if (this._closed) return this.createJsonErrorResponse(404, -32001, "Session not found"); const isInitializationRequest = messages.some((element) => require_src.isInitializeRequest(element)); if (isInitializationRequest) { if (this._initialized && this.sessionId !== void 0) { this.onerror?.(/* @__PURE__ */ new Error("Invalid Request: Server already initialized")); return this.createJsonErrorResponse(400, -32600, "Invalid Request: Server already initialized"); } if (messages.length > 1) { this.onerror?.(/* @__PURE__ */ new Error("Invalid Request: Only one initialization request is allowed")); return this.createJsonErrorResponse(400, -32600, "Invalid Request: Only one initialization request is allowed"); } this.sessionId = this.sessionIdGenerator?.(); this._initialized = true; if (this.sessionId && this._onsessioninitialized) await Promise.resolve(this._onsessioninitialized(this.sessionId)); } if (!isInitializationRequest) { const sessionError = this.validateSession(req); if (sessionError) return sessionError; const protocolError = this.validateProtocolVersion(req); if (protocolError) return protocolError; } if (this._closed) return this.createJsonErrorResponse(404, -32001, "Session not found"); let scopeChallengeResponse; try { scopeChallengeResponse = await this._checkScopeChallenge(messages, options?.authInfo); } catch (error) { this.onerror?.(error); return this.createJsonErrorResponse(500, -32603, "Internal server error"); } if (scopeChallengeResponse) return scopeChallengeResponse; if (!messages.some((element) => require_src.isJSONRPCRequest(element))) { for (const message of messages) this.onmessage?.(message, { authInfo: options?.authInfo, request }); return new Response(null, { status: 202 }); } const streamId = crypto.randomUUID(); const initRequest = messages.find((m) => require_src.isInitializeRequest(m)); const clientProtocolVersion = initRequest ? initRequest.params.protocolVersion : req.headers.get("mcp-protocol-version") ?? _modelcontextprotocol_core_internal.DEFAULT_NEGOTIATED_PROTOCOL_VERSION; if (this._enableJsonResponse) return new Promise((resolve) => { this._streamMapping.set(streamId, { resolveJson: resolve, cleanup: () => { this._streamMapping.delete(streamId); } }); for (const message of messages) if (require_src.isJSONRPCRequest(message)) this._requestToStreamMapping.set(message.id, streamId); for (const message of messages) this.onmessage?.(message, { authInfo: options?.authInfo, request }); }); const encoder = new TextEncoder(); let streamController; let keepAliveTimer; const readable = new ReadableStream({ start: (controller) => { streamController = controller; }, cancel: () => { if (keepAliveTimer !== void 0) clearInterval(keepAliveTimer); if (this._streamMapping.get(streamId)?.controller === streamController) this._streamMapping.delete(streamId); } }); const headers = { "Content-Type": "text/event-stream", "Cache-Control": "no-cache, no-transform", Connection: "keep-alive", "X-Accel-Buffering": "no" }; if (this.sessionId !== void 0) headers["mcp-session-id"] = this.sessionId; for (const message of messages) if (require_src.isJSONRPCRequest(message)) { this._streamMapping.set(streamId, { controller: streamController, encoder, cleanup: () => { if (keepAliveTimer !== void 0) clearInterval(keepAliveTimer); this._streamMapping.delete(streamId); try { streamController.close(); } catch {} } }); this._requestToStreamMapping.set(message.id, streamId); } await this.writePrimingEvent(streamController, encoder, streamId, clientProtocolVersion); for (const message of messages) { let closeSSEStream; let closeStandaloneSSEStream; if (require_src.isJSONRPCRequest(message) && this._eventStore && this.supportsEmptySSEData(clientProtocolVersion)) { closeSSEStream = () => { this.closeSSEStream(message.id); }; closeStandaloneSSEStream = () => { this.closeStandaloneSSEStream(); }; } this.onmessage?.(message, { authInfo: options?.authInfo, request, closeSSEStream, closeStandaloneSSEStream }); } if (this._streamMapping.get(streamId)?.controller === streamController) keepAliveTimer = this.startKeepAlive(streamController, encoder); return new Response(readable, { status: 200, headers }); } catch (error) { this.onerror?.(error); return this.createJsonErrorResponse(400, -32700, "Parse error", { data: String(error) }); } } /** * Handles `DELETE` requests to terminate sessions */ async handleDeleteRequest(req) { const sessionError = this.validateSession(req); if (sessionError) return sessionError; const protocolError = this.validateProtocolVersion(req); if (protocolError) return protocolError; try { await Promise.resolve(this._onsessionclosed?.(this.sessionId)); return new Response(null, { status: 200 }); } finally { await this.close(); } } /** * Validates session ID for non-initialization requests. * Returns `Response` error if invalid, `undefined` otherwise */ validateSession(req) { if (this.sessionIdGenerator === void 0) return; if (!this._initialized) { this.onerror?.(/* @__PURE__ */ new Error("Bad Request: Server not initialized")); return this.createJsonErrorResponse(400, -32e3, "Bad Request: Server not initialized"); } const sessionId = req.headers.get("mcp-session-id"); if (!sessionId) { this.onerror?.(/* @__PURE__ */ new Error("Bad Request: Mcp-Session-Id header is required")); return this.createJsonErrorResponse(400, -32e3, "Bad Request: Mcp-Session-Id header is required"); } if (sessionId !== this.sessionId) { this.onerror?.(/* @__PURE__ */ new Error("Session not found")); return this.createJsonErrorResponse(404, -32001, "Session not found"); } } /** * Validates the `MCP-Protocol-Version` header on incoming requests. * * For initialization: Version negotiation handles unknown versions gracefully * (server responds with its supported version). * * For subsequent requests with `MCP-Protocol-Version` header: * - Accept if in supported list * - 400 if unsupported * * For HTTP requests without the `MCP-Protocol-Version` header: * - Accept and default to the version negotiated at initialization */ validateProtocolVersion(req) { const protocolVersion = req.headers.get("mcp-protocol-version"); if (protocolVersion !== null && !this._supportedProtocolVersions.includes(protocolVersion)) { const error = `Bad Request: Unsupported protocol version: ${protocolVersion} (supported versions: ${this._supportedProtocolVersions.join(", ")})`; this.onerror?.(new Error(error)); return this.createJsonErrorResponse(400, -32e3, error); } } async close() { if (this._closed) return; this._closed = true; for (const { cleanup } of this._streamMapping.values()) cleanup(); this._streamMapping.clear(); this._requestResponseMap.clear(); this.onclose?.(); } /** * 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) { const streamId = this._requestToStreamMapping.get(requestId); if (!streamId) return; const stream = this._streamMapping.get(streamId); if (stream) stream.cleanup(); } /** * Close the standalone `GET` SSE stream, triggering client reconnection. * Use this to implement polling behavior for server-initiated notifications. */ closeStandaloneSSEStream() { const stream = this._streamMapping.get(this._standaloneSseStreamId); if (stream) stream.cleanup(); } async send(message, options) { let requestId = options?.relatedRequestId; if (require_src.isJSONRPCResultResponse(message) || require_src.isJSONRPCErrorResponse(message)) requestId = message.id; if (requestId === void 0) { if (require_src.isJSONRPCResultResponse(message) || require_src.isJSONRPCErrorResponse(message)) throw new Error("Cannot send a response on a standalone SSE stream unless resuming a previous client request"); let eventId; if (this._eventStore) eventId = await this._eventStore.storeEvent(this._standaloneSseStreamId, message); const standaloneSse = this._streamMapping.get(this._standaloneSseStreamId); if (standaloneSse === void 0) return; if (standaloneSse.controller && standaloneSse.encoder && (eventId === void 0 || !standaloneSse.replayedEventIds?.has(eventId))) this.writeSSEEvent(standaloneSse.controller, standaloneSse.encoder, message, eventId); return; } const streamId = this._requestToStreamMapping.get(requestId); if (!streamId) throw new Error(`No connection established for request ID: ${String(requestId)}`); let stream = this._streamMapping.get(streamId); if (!this._enableJsonResponse) { let eventId; if (this._eventStore) { eventId = await this._eventStore.storeEvent(streamId, message); stream = this._streamMapping.get(streamId); } if (stream?.controller && stream?.encoder && (eventId === void 0 || !stream.replayedEventIds?.has(eventId))) this.writeSSEEvent(stream.controller, stream.encoder, message, eventId); } if (require_src.isJSONRPCResultResponse(message) || require_src.isJSONRPCErrorResponse(message)) { this._requestResponseMap.set(requestId, message); const relatedIds = [...this._requestToStreamMapping.entries()].filter(([_, sid]) => sid === streamId).map(([id]) => id); if (relatedIds.every((id) => this._requestResponseMap.has(id))) { if (!stream) { if (this._enableJsonResponse) throw new Error(`No connection established for request ID: ${String(requestId)}`); if (!this._eventStore) { this.onerror?.(/* @__PURE__ */ new Error(`Response for request ID ${String(requestId)} is undeliverable: per-request stream is disconnected and no eventStore is configured`)); for (const id of relatedIds) { this._requestResponseMap.delete(id); this._requestToStreamMapping.delete(id); } return; } for (const id of relatedIds) { this._requestResponseMap.delete(id); this._requestToStreamMapping.delete(id); } return; } if (this._enableJsonResponse && stream.resolveJson) { const headers = { "Content-Type": "application/json" }; if (this.sessionId !== void 0) headers["mcp-session-id"] = this.sessionId; const responses = relatedIds.map((id) => this._requestResponseMap.get(id)); if (responses.length === 1) stream.resolveJson(Response.json(responses[0], { status: 200, headers })); else stream.resolveJson(Response.json(responses, { status: 200, headers })); stream.cleanup(); } else stream.cleanup(); for (const id of relatedIds) { this._requestResponseMap.delete(id); this._requestToStreamMapping.delete(id); } } } } }; //#endregion //#region src/server/createMcpHandler.ts /** * The JSON-RPC id to echo on an entry-built error response: the body's `id` * when the body is a single JSON-RPC request whose id is a string or number, * `null` otherwise. Error responses must carry the id of the request they * correspond to whenever it could be read; `null` is reserved for the cases * where no single request id is determinable — unparseable bodies, body-less * methods, notifications, posted responses and batch arrays. */ function echoableRequestId(body) { if (body === null || typeof body !== "object" || Array.isArray(body)) return null; const { method, id } = body; if (typeof method !== "string") return null; return typeof id === "string" || typeof id === "number" ? id : null; } function jsonRpcErrorResponse(httpStatus, code, message, data, id = null) { return Response.json({ jsonrpc: "2.0", error: { code, message, ...data !== void 0 && { data } }, id }, { status: httpStatus }); } function rejectionResponse(rejection, id = null) { return jsonRpcErrorResponse(rejection.httpStatus, rejection.code, rejection.message, rejection.data, id); } function toError(value) { return value instanceof Error ? value : new Error(String(value)); } function internalServerErrorResponse(id = null) { return jsonRpcErrorResponse(500, -32603, "Internal server error", void 0, id); } /** Throws when the factory returned an instance that is still connected to another exchange. */ function assertNotServing(server) { if (server.transport !== void 0) throw new Error("The factory returned an instance that is still serving another request. Return a new instance for each request."); } /** * The entry's default legacy serving (`legacy: 'stateless'`): per-request * stateless serving of 2025-era traffic using the same factory as the modern * path. Exported as a standalone building block for hand-wired compositions * (for example mounting legacy stateless serving on its own route next to a * strict modern endpoint). * * Each POST is served by a fresh instance from the factory connected to a * fresh streamable HTTP transport constructed with only * `sessionIdGenerator: undefined` — the established stateless idiom, unchanged. * Because serving is per-request and stateless, GET and DELETE (2025 session * operations) are answered with `405` / `Method not allowed.`, exactly like the * canonical stateless example. * * The optional `onerror` callback receives factory and serving failures on * this leg (reporting only — the response stays the 500 internal-error body). * The entry passes its own `onerror` here when expanding the default, so * legacy-leg failures are never silently swallowed. */ function createLegacyStatelessFallback(factory, onerror, keepAliveMs, maxRequestBodySize) { return async (request, options) => { if (request.method.toUpperCase() !== "POST") return jsonRpcErrorResponse(405, -32e3, "Method not allowed."); try { const product = await factory({ era: "legacy", ...options?.authInfo !== void 0 && { authInfo: options.authInfo }, requestInfo: request }); const transport = new WebStandardStreamableHTTPServerTransport({ sessionIdGenerator: void 0, ...keepAliveMs !== void 0 && { keepAliveMs }, ...maxRequestBodySize !== void 0 && { maxRequestBodySize } }); await product.connect(transport); const teardown = () => { transport.close().catch(() => {}); product.close().catch(() => {}); }; request.signal?.addEventListener("abort", teardown, { once: true }); const response = await transport.handleRequest(request, { ...options?.authInfo !== void 0 && { authInfo: options.authInfo }, ...options?.parsedBody !== void 0 && { parsedBody: options.parsedBody } }); if (response.body === null || require_src.mediaTypeEssence(response.headers.get("content-type")) !== "text/event-stream") { teardown(); return response; } const reader = response.body.getReader(); let toreDown = false; const completeExchange = () => { if (!toreDown) { toreDown = true; teardown(); } }; const monitoredBody = new ReadableStream({ pull: async (controller) => { try { const { done, value } = await reader.read(); if (done) { completeExchange(); controller.close(); return; } if (value !== void 0) controller.enqueue(value); } catch (error) { completeExchange(); controller.error(error); } }, cancel: (reason) => { completeExchange(); return reader.cancel(reason).catch(() => {}); } }); return new Response(monitoredBody, { status: response.status, statusText: response.statusText, headers: response.headers }); } catch (error) { try { onerror?.(toError(error)); } catch {} return internalServerErrorResponse(echoableRequestId(options?.parsedBody)); } }; } function legacyStatelessFallback(factory, onerror, options) { return createLegacyStatelessFallback(factory, onerror, void 0, resolveMaxRequestBodySize(options?.maxRequestBodySize)); } /** * Read the SEP-2243 standard request headers off the inbound request. * * Both halves of the standard-header story need them — the body-primary * classifier for its cross-check cells, and * {@linkcode validateStandardRequestHeaders} for the presence half — and a * header read at one site but not the other is precisely how a required header * goes unenforced: that divergence is what let a modern POST omitting * `MCP-Protocol-Version` be served. Read them here once so a header added to * {@linkcode InboundHttpRequest} reaches both sites together. */ function standardHeadersOf(request) { return { protocolVersionHeader: request.headers.get("mcp-protocol-version") ?? void 0, mcpMethodHeader: request.headers.get("mcp-method") ?? void 0, mcpNameHeader: request.headers.get("mcp-name") ?? void 0 }; } /** * The entry's classification step: read the request body exactly once (unless * a pre-parsed body is supplied) and classify the request with * {@linkcode classifyInboundRequest}. This is the single code path behind both * {@linkcode createMcpHandler}'s routing and the exported * {@linkcode isLegacyRequest} predicate, so the two can never disagree. * * Pass `needsForward: false` when the caller never reads `forwardRequest` — * the body-preserving clone is then skipped and `forwardRequest` is the * (consumed) input request. */ async function classifyEntryRequest(request, providedParsedBody, needsForward = true, maxRequestBodySize = DEFAULT_MAX_REQUEST_BODY_SIZE) { const httpMethod = request.method.toUpperCase(); let body; let parsedBody = providedParsedBody; let forwardRequest = request; let unparseable = false; if (httpMethod === "POST") { if (parsedBody === void 0) { if (needsForward) forwardRequest = request.clone(); let bodyText; try { const read = await readRequestBody(request, maxRequestBodySize); if (read.tooLarge) return { step: "body-too-large" }; bodyText = read.text; } catch { return { step: "unreadable-body" }; } try { body = bodyText.length === 0 ? void 0 : JSON.parse(bodyText); } catch { unparseable = true; } if (!unparseable && body !== void 0) parsedBody = body; } else body = parsedBody; if (unparseable || body === void 0) return { step: "no-json-body", forwardRequest }; } return { step: "classified", outcome: require_src.classifyInboundRequest({ httpMethod, ...standardHeadersOf(request), ...body !== void 0 && { body } }), body, parsedBody, forwardRequest }; } /** * Whether {@linkcode createMcpHandler} would route this request to its legacy * (2025-era) serving rather than the modern (2026-07-28) path. * * Call it with just the request: `await isLegacyRequest(request)`. For a * `POST` the body is read from an internal clone, so the request you pass * stays fully readable for whichever handler you route it to — no second * argument is needed. (In a Node `(req, res)` handler, build that `Request` * with `toWebRequest(req)` from `@modelcontextprotocol/node`; behind a body * parser, which has already drained the Node stream, build it as * `toWebRequest(req, req.body)` so the bytes come from the parsed body — * either way the predicate still takes just the request.) The optional * `parsedBody` is a perf escape hatch for a body you already hold parsed: * pass it and the predicate classifies from the value directly, reading and * cloning nothing. It is needed, not just faster, when the request's own * body was already read — the internal clone is then impossible (cloning a * used body throws a `TypeError`), so such a single-argument call rejects * instead of guessing. * * This is the entry's own classification step exported as a predicate — it * runs exactly the code `createMcpHandler` runs to make the routing decision, * not a re-implementation — so a hand-wired composition that branches on it * can never disagree with the entry. It is classification only: hand-wired * compositions must validate Content-Type themselves (415 for POSTs whose * media type is not `application/json`, via {@linkcode isJsonContentType}) * before dispatching either leg — routing the legacy leg into the SDK * transports gets their built-in check, but a custom modern leg has none. Use it to keep an existing legacy * deployment (for example a sessionful streamable HTTP wiring) serving 2025 * traffic next to a strict modern endpoint, now that the entry has no * handler-valued `legacy` option: * * ```ts * import { createMcpHandler, isLegacyRequest } from '@modelcontextprotocol/server'; * * const modern = createMcpHandler(factory, { legacy: 'reject' }); * * export default { * async fetch(request: Request): Promise { * if (await isLegacyRequest(request)) { * // e.g. an existing sessionful WebStandardStreamableHTTPServerTransport wiring * return myExistingLegacyHandler(request); * } * return modern.fetch(request); * } * }; * ``` * * Semantics (identical to the entry's routing): * * - Returns `true` only for requests with no per-request `_meta` envelope * claim: claim-less POSTs (including the `initialize` handshake and 2025-era * notification POSTs without a modern protocol-version header), body-less * GET/DELETE session operations, all-legacy JSON-RPC batch arrays, posted * JSON-RPC responses, and POSTs whose body is empty or not valid JSON. * - Returns `false` for everything the modern path answers, including its * validation-ladder rejections: a request carrying the envelope claim (even * one naming a revision the endpoint does not serve — the modern path * answers it with the unsupported-protocol-version error), a malformed * envelope behind a present claim (answered `-32602`), a request whose * `MCP-Protocol-Version` header names a modern revision but that lacks the * envelope (`-32602`), header/body mismatches (`-32020`), and a POST body * over the size limit (413). Consumers * routing on the predicate must send `false` traffic to the modern handler, * never to a legacy handler — the modern path owns those error answers. * - `server/discover` probes sent by negotiating clients always carry the * envelope claim, so they are never legacy; a hand-built claim-less POST to * a method named `server/discover` has no claim and classifies legacy, * exactly as the entry itself routes it. */ async function isLegacyRequest(request, parsedBody, options) { const maxRequestBodySize = resolveMaxRequestBodySize(options?.maxRequestBodySize); const classified = await classifyEntryRequest(parsedBody === void 0 && request.method.toUpperCase() === "POST" ? request.clone() : request, parsedBody, false, maxRequestBodySize); return classified.step === "no-json-body" || classified.step === "classified" && classified.outcome.kind === "legacy"; } /** * Creates an HTTP handler that serves the 2026-07-28 protocol revision from a * per-request server factory and, by default, falls back to old-school * stateless serving for 2025-era traffic. Pass `legacy: 'reject'` for a * modern-only strict endpoint. * * Mounting: `handler.fetch` is the web-standard face (Cloudflare Workers, * Deno, Bun, Hono's `c.req.raw`); for Express/Fastify/plain `node:http`, wrap * the handler once with `toNodeHandler(handler)` from * `@modelcontextprotocol/node`. When mounting bare on a fetch-native runtime, * put Origin/Host validation in front of the handler — the entry itself is * deliberately validation-free: * * ```ts * import { hostHeaderValidationResponse, originValidationResponse, localhostAllowedHostnames, localhostAllowedOrigins } from '@modelcontextprotocol/server'; * * export default { * async fetch(request: Request): Promise { * const rejected = * hostHeaderValidationResponse(request, localhostAllowedHostnames()) ?? * originValidationResponse(request, localhostAllowedOrigins()); * return rejected ?? handler.fetch(request); * } * }; * ``` * * Use ONE factory for both legs: the same tools/resources/prompts definition * backs the modern path and the stateless legacy fallback, so the two eras can * never drift apart. To keep an existing legacy deployment (for example a * sessionful streamable HTTP wiring) serving 2025 traffic instead of the * stateless fallback, route in user land with {@linkcode isLegacyRequest} in * front of a strict handler — see that predicate's documentation for the * pattern. Power users composing transport-neutral routing can also use the * exported building blocks directly: {@linkcode classifyInboundRequest} for * the era decision and `PerRequestHTTPServerTransport` for single-exchange * serving — such compositions must reject POSTs whose Content-Type media type * is not `application/json` (415) before parsing the body, using * {@linkcode isJsonContentType}; neither building block performs this * validation itself. * * The entry performs no token verification: `authInfo` given to `fetch` is * passed through to handlers and the factory as-is and is never derived from * request headers. */ function createMcpHandler(factory, options = {}) { const { legacy, onerror, responseMode } = options; const maxRequestBodySize = resolveMaxRequestBodySize(options.maxRequestBodySize); if (typeof legacy === "function") throw new TypeError("The 'legacy' option only accepts 'stateless' or 'reject', not a handler function. To serve 2025-era traffic with your own handler, route in user land with the exported isLegacyRequest(request) predicate in front of a strict (legacy: 'reject') handler."); /** Modern per-request instances with an exchange still in flight (close() tears these down). */ const inflight = /* @__PURE__ */ new Set(); let closed = false; const reportError = (error) => { try { onerror?.(error); } catch {} }; const bus = options.bus ?? new require_mcp.InMemoryServerEventBus(reportError); const notify = require_mcp.createServerNotifier(bus); const listenRouter = require_mcp.createListenRouter({ bus, maxSubscriptions: options.maxSubscriptions ?? require_mcp.DEFAULT_MAX_SUBSCRIPTIONS, keepAliveMs: options.keepAliveMs ?? require_mcp.DEFAULT_SSE_KEEP_ALIVE_MS, onerror: reportError }); if (responseMode === "json") console.warn("responseMode: 'json' drops mid-call notifications. subscriptions/listen streams are always served over SSE regardless; other notifications emitted before a result are dropped."); const legacyHandler = legacy === "reject" ? void 0 : createLegacyStatelessFallback(factory, reportError, options.keepAliveMs, maxRequestBodySize); async function serveModern(route, request, authInfo) { const claimedRevision = route.classification.revision; if (claimedRevision === void 0 || !require_src.SUPPORTED_MODERN_PROTOCOL_VERSIONS.includes(claimedRevision)) { const error = new require_src.UnsupportedProtocolVersionError({ supported: [...require_src.SUPPORTED_MODERN_PROTOCOL_VERSIONS], requested: claimedRevision ?? "unknown" }); reportError(error); return jsonRpcErrorResponse(400, error.code, error.message, error.data, echoableRequestId(route.message)); } const stdHeaderRejection = require_src.validateStandardRequestHeaders({ httpMethod: request.method, ...standardHeadersOf(request) }, route); if (stdHeaderRejection !== void 0) { reportError(/* @__PURE__ */ new Error(`Rejected inbound request (${stdHeaderRejection.cell}): ${stdHeaderRejection.message}`)); return rejectionResponse(stdHeaderRejection, echoableRequestId(route.message)); } const meta = route.messageKind === "request" ? require_src.requestMetaOf(route.message.params) : void 0; const declaredClientCapabilities = meta?.[_modelcontextprotocol_core_internal.CLIENT_CAPABILITIES_META_KEY]; if (route.messageKind === "request") { const required = require_src.requiredClientCapabilitiesForRequest(route.message.method); if (required !== void 0) { const missing = require_src.missingClientCapabilities(required, declaredClientCapabilities); if (missing !== void 0) { const error = new require_src.MissingRequiredClientCapabilityError({ requiredCapabilities: missing }); reportError(error); return jsonRpcErrorResponse(require_src.httpStatusForErrorCode(error.code, "ladder"), error.code, error.message, error.data, route.message.id); } } } const product = await factory({ era: "modern", ...authInfo !== void 0 && { authInfo }, requestInfo: request }); const server = product instanceof require_mcp.McpServer ? product.server : product; assertNotServing(server); if (route.messageKind === "request" && route.message.method === "subscriptions/listen") { const capabilities = server.getCapabilities(); const serverInfo = require_mcp.serverIdentityOf(server); product.close().catch(reportError); return listenRouter.serve(route.message, request.signal, capabilities, serverInfo); } if (route.messageKind === "request" && route.message.method === "tools/call" && product instanceof require_mcp.McpServer) { const callParams = route.message.params; const toolName = typeof callParams?.name === "string" ? callParams.name : void 0; const inputSchema = toolName === void 0 ? void 0 : product.toolInputSchemaJson(toolName); if (inputSchema !== void 0) { const scan = require_src.scanXMcpHeaderDeclarations(inputSchema); if (scan.valid && scan.declarations.length > 0) { const rejection = require_src.validateMcpParamHeaders(scan.declarations, callParams?.arguments, request.headers); if (rejection !== void 0) { product.close().catch(reportError); reportError(/* @__PURE__ */ new Error(`Rejected inbound request (${rejection.cell}): ${rejection.message}`)); return rejectionResponse(rejection, route.message.id); } } } } if (route.messageKind === "request" && product instanceof require_mcp.McpServer) try { const challenge = await require_mcp.findScopeChallenge([route.message], authInfo, (context) => product.resolveScopeChallenge(context)); if (challenge !== void 0) { product.close().catch(reportError); return require_mcp.createScopeChallengeResponse(challenge, require_mcp.scopeChallengeResourceMetadataUrl(authInfo)); } } catch (error) { product.close().catch(reportError); reportError(toError(error)); return internalServerErrorResponse(route.message.id); } assertNotServing(server); require_src.setNegotiatedProtocolVersion(server, claimedRevision); require_mcp.installModernOnlyHandlers(server, require_src.SUPPORTED_MODERN_PROTOCOL_VERSIONS); if (meta !== void 0) require_mcp.seedClientIdentityFromEnvelope(server, { clientInfo: meta[_modelcontextprotocol_core_internal.CLIENT_INFO_META_KEY], clientCapabilities: declaredClientCapabilities }); const previousOnClose = server.onclose; inflight.add(server); const onExchangeClose = () => { inflight.delete(server); if (server.onclose === onExchangeClose) server.onclose = previousOnClose; previousOnClose?.(); }; server.onclose = onExchangeClose; try { const response = await invoke(product, route.message, { classification: route.classification, request, ...authInfo !== void 0 && { authInfo }, ...responseMode !== void 0 && { responseMode }, ...options.keepAliveMs !== void 0 && { keepAliveMs: options.keepAliveMs } }); if (route.messageKind === "notification") queueMicrotask(() => void server.close().catch(() => {})); return response; } catch (error) { if (error instanceof require_src.SdkError && error.code === require_src.SdkErrorCode.ConnectionClosed) return new Response(null, { status: 499 }); await server.close().catch(() => {}); inflight.delete(server); reportError(toError(error)); return internalServerErrorResponse(echoableRequestId(route.message)); } } async function serveLegacyRoute(route, forwardRequest, authInfo, parsedBody) { if (legacyHandler !== void 0) return legacyHandler(forwardRequest, { ...authInfo !== void 0 && { authInfo }, ...parsedBody !== void 0 && { parsedBody } }); const strict = require_src.modernOnlyStrictRejection(route, require_src.SUPPORTED_MODERN_PROTOCOL_VERSIONS); if (strict === void 0) return new Response(null, { status: 202 }); reportError(/* @__PURE__ */ new Error(`Rejected 2025-era request on a modern-only endpoint (${strict.cell}): ${strict.message}`)); return rejectionResponse(strict, echoableRequestId(parsedBody)); } async function handle(request, requestOptions) { const authInfo = requestOptions?.authInfo; if (request.method.toUpperCase() === "POST" && !require_src.isJsonContentType(request.headers.get("content-type"))) { reportError(/* @__PURE__ */ new Error("Unsupported Media Type: Content-Type must be application/json")); return jsonRpcErrorResponse(415, -32e3, "Unsupported Media Type: Content-Type must be application/json"); } const classified = await classifyEntryRequest(request, requestOptions?.parsedBody, true, maxRequestBodySize); if (classified.step === "unreadable-body") return jsonRpcErrorResponse(400, -32700, "Parse error: the request body could not be read"); if (classified.step === "body-too-large") return jsonRpcErrorResponse(413, -32e3, requestBodyTooLargeMessage(maxRequestBodySize)); if (classified.step === "no-json-body") { if (legacyHandler !== void 0) return legacyHandler(classified.forwardRequest, { ...authInfo !== void 0 && { authInfo } }); return jsonRpcErrorResponse(400, -32700, "Parse error: the request body is not valid JSON"); } const { outcome, body, parsedBody, forwardRequest } = classified; try { switch (outcome.kind) { case "reject": reportError(/* @__PURE__ */ new Error(`Rejected inbound request (${outcome.cell}): ${outcome.message}`)); return rejectionResponse(outcome, echoableRequestId(body)); case "modern": return await serveModern(outcome, request, authInfo); case "legacy": return await serveLegacyRoute(outcome, forwardRequest, authInfo, parsedBody); } } catch (error) { reportError(toError(error)); return internalServerErrorResponse(echoableRequestId(body)); } } const fetchFace = async (request, requestOptions) => { if (closed) throw new Error("This MCP handler has been closed"); try { return await handle(request, requestOptions); } catch (error) { reportError(toError(error)); return internalServerErrorResponse(echoableRequestId(requestOptions?.parsedBody)); } }; return { fetch: fetchFace, notify, bus, close: async () => { closed = true; listenRouter.closeAll(); const closing = [...inflight].map((server) => server.close().catch(() => {})); inflight.clear(); await Promise.all(closing); } }; } //#endregion //#region src/server/middleware/hostHeaderValidation.ts /** * Parse and validate a `Host` header against an allowlist of hostnames (port-agnostic). * * - Input host header may include a port (e.g. `localhost:3000`) or IPv6 brackets (e.g. `[::1]:3000`). * - Allowlist items should be hostnames only (no ports). For IPv6, include brackets (e.g. `[::1]`). */ function validateHostHeader(hostHeader, allowedHostnames) { if (!hostHeader) return { ok: false, errorCode: "missing_host", message: "Missing Host header" }; let hostname; try { hostname = new URL(`http://${hostHeader}`).hostname; } catch { return { ok: false, errorCode: "invalid_host_header", message: `Invalid Host header: ${hostHeader}`, hostHeader }; } if (!allowedHostnames.includes(hostname)) return { ok: false, errorCode: "invalid_host", message: `Invalid Host: ${hostname}`, hostHeader, hostname }; return { ok: true, hostname }; } /** * Convenience allowlist for `localhost` DNS rebinding protection. */ function localhostAllowedHostnames() { return [ "localhost", "127.0.0.1", "[::1]" ]; } /** * Web-standard `Request` helper for DNS rebinding protection. * @example * ```ts source="./hostHeaderValidation.examples.ts#hostHeaderValidationResponse_basicUsage" * const result = validateHostHeader(req.headers.get('host'), ['localhost']); * ``` */ function hostHeaderValidationResponse(req, allowedHostnames) { const result = validateHostHeader(req.headers.get("host"), allowedHostnames); if (result.ok) return void 0; return Response.json({ jsonrpc: "2.0", error: { code: -32e3, message: result.message }, id: null }, { status: 403, headers: { "Content-Type": "application/json" } }); } //#endregion //#region src/server/middleware/originValidation.ts /** * Validate an `Origin` header against an allowlist of hostnames (port-agnostic). * * - A missing/empty `Origin` header passes: non-browser clients do not send one, * and only browser-originated requests carry the header this check defends against. * - Allowlist items are hostnames only (no scheme, no port), the same convention as * `validateHostHeader`. For IPv6, include brackets (e.g. `[::1]`). * - A browser extension's origin carries its extension ID as the hostname; list the * ID to allow one extension. An allowlist item of the form `://*` * (lowercase, e.g. `moz-extension://*`) allows every origin of that scheme, which * Firefox needs because its extension IDs differ on every install. * `http://*` and `https://*` are not honoured: list websites by hostname. * - Any present value that cannot be parsed as an origin URL — including the literal * `null` origin browsers send for opaque contexts — is rejected (deny on failure). */ function validateOriginHeader(originHeader, allowedOriginHostnames) { if (originHeader === null || originHeader === void 0 || originHeader === "") return { ok: true }; let hostname; let scheme; try { const url = new URL(originHeader); hostname = url.hostname; scheme = url.protocol; } catch { return { ok: false, errorCode: "invalid_origin_header", message: `Invalid Origin header: ${originHeader}`, originHeader }; } if (hostname === "") return { ok: false, errorCode: "invalid_origin_header", message: `Invalid Origin header: ${originHeader}`, originHeader }; if (!(scheme !== "http:" && scheme !== "https:" && allowedOriginHostnames.includes(`${scheme}//*`)) && !allowedOriginHostnames.includes(hostname)) return { ok: false, errorCode: "invalid_origin", message: `Invalid Origin: ${hostname}`, originHeader, hostname }; return { ok: true, origin: originHeader, hostname }; } /** * Convenience allowlist of localhost-class origin hostnames, mirroring * `localhostAllowedHostnames`. */ function localhostAllowedOrigins() { return [ "localhost", "127.0.0.1", "[::1]" ]; } /** * Web-standard `Request` helper for Origin validation: returns a `403` JSON-RPC * error response when the request's `Origin` header is not allowed, and * `undefined` when the request may proceed. * * ```ts * const rejected = originValidationResponse(request, localhostAllowedOrigins()); * if (rejected) return rejected; * ``` */ function originValidationResponse(req, allowedOriginHostnames) { const result = validateOriginHeader(req.headers.get("origin"), allowedOriginHostnames); if (result.ok) return void 0; return Response.json({ jsonrpc: "2.0", error: { code: -32e3, message: result.message }, id: null }, { status: 403, headers: { "Content-Type": "application/json" } }); } //#endregion //#region src/server/requestStateCodec.ts const PREFIX = "v1."; function bytesToBase64Url(bytes) { let bin = ""; for (const b of bytes) bin += String.fromCodePoint(b); return btoa(bin).replaceAll("+", "-").replaceAll("/", "_").replace(/=+$/, ""); } function constantTimeTagEqual(a, b) { if (a.length !== b.length) return false; let r = 0; for (let i = 0; i < a.length; i++) r |= a.codePointAt(i) ^ b.codePointAt(i); return r === 0; } function base64UrlToBytes(s) { const b64 = s.replaceAll("-", "+").replaceAll("_", "/"); const bin = atob(b64); const bytes = new Uint8Array(bin.length); for (let i = 0; i < bin.length; i++) bytes[i] = bin.codePointAt(i); return bytes; } /** * Create an opt-in HMAC-SHA256 codec for the multi-round-trip `requestState` * (protocol revision 2026-07-28). * * `requestState` round-trips through the client and is attacker-controlled * input on re-entry. The SDK applies no protection of its own; this helper is * the convenience implementation of the spec's integrity MUST so authors don't * hand-roll HMAC. Wire shape: * * "v1." b64url({"p":,"exp":,"b":?}) "." b64url(mac) * * where `bindTag` is `b64url(HMAC(key, "mcp.requestState.bind:" + bind(ctx))[:16])` * — the binding value is never embedded raw. * * The codec is **signed, not encrypted**: the body is integrity-protected but * the client can base64url-decode it and read the payload (`p`) in clear. Do * not put secrets in the payload; use an AEAD construction if confidentiality * is required. The handler reads its payload back via the typed * `ctx.mcpReq.requestState()` accessor — the seam has already run `verify` * (integrity proven, payload decoded) by the time the handler is entered. * * Verification is fail-closed and constant-time (WebCrypto `subtle.verify` for * the body MAC; a fixed-length XOR-accumulator compare for the bind tag). * See `examples/mrtr/server.ts` for a worked end-to-end example. * * Design comparison (mcp.d `secureRequestState`, the peer SDK's reference * implementation): mcp.d additionally offers an AES-256-GCM encrypted mode and * derives independent cipher / bind-HMAC sub-keys from the operator secret via * HKDF-SHA256, with an auto-generated per-process ephemeral key when none is * supplied. This codec deliberately ships only the signed mode and a single * keyed HMAC (domain-separated by input prefix) — HKDF sub-key derivation and * an encrypted mode are intentionally out of scope for the initial release. */ function createRequestStateCodec(options) { const subtle = globalThis.crypto?.subtle; if (subtle === void 0) throw new TypeError("createRequestStateCodec requires the Web Crypto API (globalThis.crypto.subtle); see https://ts.sdk.modelcontextprotocol.io/v2/troubleshooting for the Node.js polyfill instructions"); const keyBytes = typeof options.key === "string" ? new TextEncoder().encode(options.key) : Uint8Array.from(options.key); if (keyBytes.byteLength < 32) throw new RangeError(`createRequestStateCodec: key must be at least 32 bytes (got ${keyBytes.byteLength})`); const ttlSeconds = options.ttlSeconds ?? 600; if (!Number.isFinite(ttlSeconds)) throw new RangeError("createRequestStateCodec: ttlSeconds must be a finite number"); const bind = options.bind; let cryptoKey; const importedKey = () => cryptoKey ??= subtle.importKey("raw", keyBytes, { name: "HMAC", hash: "SHA-256" }, false, ["sign", "verify"]); const utf8 = new TextEncoder(); const BIND_LABEL = "mcp.requestState.bind:"; const bindTag = async (value) => { return bytesToBase64Url(new Uint8Array(await subtle.sign("HMAC", await importedKey(), utf8.encode(BIND_LABEL + value))).slice(0, 16)); }; return { async mint(payload, ctx) { const envelope = { p: payload, exp: Math.floor(Date.now() / 1e3) + ttlSeconds }; if (bind !== void 0) { if (ctx === void 0) throw new TypeError("createRequestStateCodec: mint() requires ctx when a bind callback is configured"); envelope.b = await bindTag(bind(ctx)); } const body = bytesToBase64Url(utf8.encode(JSON.stringify(envelope))); return `${PREFIX}${body}.${bytesToBase64Url(new Uint8Array(await subtle.sign("HMAC", await importedKey(), utf8.encode(PREFIX + body))))}`; }, async verify(state, ctx) { const dot = state.lastIndexOf("."); if (!state.startsWith(PREFIX) || dot <= 3) throw new Error("malformed"); const body = state.slice(3, dot); let macBytes; try { macBytes = base64UrlToBytes(state.slice(dot + 1)); } catch { throw new Error("malformed"); } if (!await subtle.verify("HMAC", await importedKey(), macBytes, utf8.encode(PREFIX + body))) throw new Error("mac"); let envelope; try { envelope = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(base64UrlToBytes(body))); } catch { throw new Error("malformed"); } if (typeof envelope.exp !== "number" || envelope.exp < Math.floor(Date.now() / 1e3)) throw new Error("expired"); if (bind !== void 0) { const expected = await bindTag(bind(ctx)); if (envelope.b === void 0 || !constantTimeTagEqual(envelope.b, expected)) throw new Error("bind"); } else if (envelope.b !== void 0) throw new Error("bind"); return envelope.p; } }; } //#endregion //#region src/fromJsonSchema.ts let _defaultValidator; function fromJsonSchema(schema, validator) { return require_src.fromJsonSchema(schema, validator ?? (_defaultValidator ??= new _modelcontextprotocol_server__shims.DefaultJsonSchemaValidator())); } //#endregion Object.defineProperty(exports, 'BAGGAGE_META_KEY', { enumerable: true, get: function () { return _modelcontextprotocol_core_internal.BAGGAGE_META_KEY; } }); Object.defineProperty(exports, 'CLIENT_CAPABILITIES_META_KEY', { enumerable: true, get: function () { return _modelcontextprotocol_core_internal.CLIENT_CAPABILITIES_META_KEY; } }); Object.defineProperty(exports, 'CLIENT_INFO_META_KEY', { enumerable: true, get: function () { return _modelcontextprotocol_core_internal.CLIENT_INFO_META_KEY; } }); exports.DEFAULT_MAX_REQUEST_BODY_SIZE = DEFAULT_MAX_REQUEST_BODY_SIZE; Object.defineProperty(exports, 'DEFAULT_NEGOTIATED_PROTOCOL_VERSION', { enumerable: true, get: function () { return _modelcontextprotocol_core_internal.DEFAULT_NEGOTIATED_PROTOCOL_VERSION; } }); exports.DEFAULT_REQUEST_TIMEOUT_MSEC = require_src.DEFAULT_REQUEST_TIMEOUT_MSEC; Object.defineProperty(exports, 'INTERNAL_ERROR', { enumerable: true, get: function () { return _modelcontextprotocol_core_internal.INTERNAL_ERROR; } }); Object.defineProperty(exports, 'INVALID_PARAMS', { enumerable: true, get: function () { return _modelcontextprotocol_core_internal.INVALID_PARAMS; } }); Object.defineProperty(exports, 'INVALID_REQUEST', { enumerable: true, get: function () { return _modelcontextprotocol_core_internal.INVALID_REQUEST; } }); exports.InMemoryServerEventBus = require_mcp.InMemoryServerEventBus; exports.InMemoryTransport = require_src.InMemoryTransport; Object.defineProperty(exports, 'JSONRPC_VERSION', { enumerable: true, get: function () { return _modelcontextprotocol_core_internal.JSONRPC_VERSION; } }); Object.defineProperty(exports, 'LATEST_PROTOCOL_VERSION', { enumerable: true, get: function () { return _modelcontextprotocol_core_internal.LATEST_PROTOCOL_VERSION; } }); Object.defineProperty(exports, 'LOG_LEVEL_META_KEY', { enumerable: true, get: function () { return _modelcontextprotocol_core_internal.LOG_LEVEL_META_KEY; } }); Object.defineProperty(exports, 'METHOD_NOT_FOUND', { enumerable: true, get: function () { return _modelcontextprotocol_core_internal.METHOD_NOT_FOUND; } }); exports.McpServer = require_mcp.McpServer; exports.MissingRequiredClientCapabilityError = require_src.MissingRequiredClientCapabilityError; exports.OAuthError = require_src.OAuthError; exports.OAuthErrorCode = require_src.OAuthErrorCode; Object.defineProperty(exports, 'PARSE_ERROR', { enumerable: true, get: function () { return _modelcontextprotocol_core_internal.PARSE_ERROR; } }); Object.defineProperty(exports, 'PROTOCOL_VERSION_META_KEY', { enumerable: true, get: function () { return _modelcontextprotocol_core_internal.PROTOCOL_VERSION_META_KEY; } }); exports.PerRequestHTTPServerTransport = PerRequestHTTPServerTransport; exports.Protocol = require_src.Protocol; exports.ProtocolError = require_src.ProtocolError; exports.ProtocolErrorCode = require_src.ProtocolErrorCode; Object.defineProperty(exports, 'RELATED_TASK_META_KEY', { enumerable: true, get: function () { return _modelcontextprotocol_core_internal.RELATED_TASK_META_KEY; } }); exports.ReadBuffer = require_src.ReadBuffer; exports.ResourceNotFoundError = require_src.ResourceNotFoundError; exports.ResourceTemplate = require_mcp.ResourceTemplate; Object.defineProperty(exports, 'SERVER_INFO_META_KEY', { enumerable: true, get: function () { return _modelcontextprotocol_core_internal.SERVER_INFO_META_KEY; } }); exports.STDIO_DEFAULT_MAX_BUFFER_SIZE = require_src.STDIO_DEFAULT_MAX_BUFFER_SIZE; Object.defineProperty(exports, 'SUBSCRIPTION_ID_META_KEY', { enumerable: true, get: function () { return _modelcontextprotocol_core_internal.SUBSCRIPTION_ID_META_KEY; } }); Object.defineProperty(exports, 'SUPPORTED_PROTOCOL_VERSIONS', { enumerable: true, get: function () { return _modelcontextprotocol_core_internal.SUPPORTED_PROTOCOL_VERSIONS; } }); exports.SdkError = require_src.SdkError; exports.SdkErrorCode = require_src.SdkErrorCode; exports.SdkHttpError = require_src.SdkHttpError; exports.Server = require_mcp.Server; Object.defineProperty(exports, 'TRACEPARENT_META_KEY', { enumerable: true, get: function () { return _modelcontextprotocol_core_internal.TRACEPARENT_META_KEY; } }); Object.defineProperty(exports, 'TRACESTATE_META_KEY', { enumerable: true, get: function () { return _modelcontextprotocol_core_internal.TRACESTATE_META_KEY; } }); exports.UnsupportedProtocolVersionError = require_src.UnsupportedProtocolVersionError; exports.UriTemplate = require_src.UriTemplate; exports.UrlElicitationRequiredError = require_src.UrlElicitationRequiredError; exports.WebStandardStreamableHTTPServerTransport = WebStandardStreamableHTTPServerTransport; exports.acceptedContent = require_src.acceptedContent; exports.assertCompleteRequestPrompt = require_src.assertCompleteRequestPrompt; exports.assertCompleteRequestResourceTemplate = require_src.assertCompleteRequestResourceTemplate; exports.bearerAuthChallengeResponse = require_mcp.bearerAuthChallengeResponse; exports.buildOAuthProtectedResourceMetadata = require_mcp.buildOAuthProtectedResourceMetadata; exports.checkResourceAllowed = require_src.checkResourceAllowed; exports.classifyInboundRequest = require_src.classifyInboundRequest; exports.completable = require_mcp.completable; exports.createFetchWithInit = require_src.createFetchWithInit; exports.createMcpHandler = createMcpHandler; exports.createRequestStateCodec = createRequestStateCodec; exports.deserializeMessage = require_src.deserializeMessage; exports.fromJsonSchema = fromJsonSchema; exports.getDisplayName = require_src.getDisplayName; exports.getOAuthProtectedResourceMetadataUrl = require_mcp.getOAuthProtectedResourceMetadataUrl; exports.hostHeaderValidationResponse = hostHeaderValidationResponse; exports.inputRequired = require_src.inputRequired; exports.inputResponse = require_src.inputResponse; exports.isCallToolResult = require_src.isCallToolResult; exports.isCompletable = require_mcp.isCompletable; exports.isInitializeRequest = require_src.isInitializeRequest; exports.isInitializedNotification = require_src.isInitializedNotification; exports.isInputRequiredResult = require_src.isInputRequiredResult; exports.isJSONRPCErrorResponse = require_src.isJSONRPCErrorResponse; exports.isJSONRPCNotification = require_src.isJSONRPCNotification; exports.isJSONRPCRequest = require_src.isJSONRPCRequest; exports.isJSONRPCResponse = require_src.isJSONRPCResponse; exports.isJSONRPCResultResponse = require_src.isJSONRPCResultResponse; exports.isJsonContentType = require_src.isJsonContentType; exports.isLegacyRequest = isLegacyRequest; exports.isSpecType = require_src.isSpecType; exports.isTaskAugmentedRequestParams = require_src.isTaskAugmentedRequestParams; exports.legacyStatelessFallback = legacyStatelessFallback; exports.localhostAllowedHostnames = localhostAllowedHostnames; exports.localhostAllowedOrigins = localhostAllowedOrigins; exports.mergeCapabilities = require_src.mergeCapabilities; exports.oauthMetadataResponse = require_mcp.oauthMetadataResponse; exports.originValidationResponse = originValidationResponse; exports.parseJSONRPCMessage = require_src.parseJSONRPCMessage; exports.preloadSchemas = require_src.preloadSchemas; exports.readRequestBody = readRequestBody; exports.requireBearerAuth = require_mcp.requireBearerAuth; exports.requireScopes = require_mcp.requireScopes; exports.resourceUrlFromServerUrl = require_src.resourceUrlFromServerUrl; exports.serializeMessage = require_src.serializeMessage; exports.specTypeSchemas = require_src.specTypeSchemas; exports.validateHostHeader = validateHostHeader; exports.validateOriginHeader = validateOriginHeader; exports.verifyBearerToken = require_mcp.verifyBearerToken; //# sourceMappingURL=index.cjs.map