{"version":3,"sources":["../src/handler/mcp-api-handler.ts","../src/lib/event-emitter.ts","../src/lib/log-helper.ts","../src/auth/auth-context.ts","../src/handler/server-response-adapter.ts","../src/handler/index.ts","../src/auth/auth-wrapper.ts","../src/lib/url.ts","../src/auth/auth-metadata.ts"],"names":["_a","redis","redisPublisher","logInContext","req","body"],"mappings":"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","sourcesContent":["import { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { SSEServerTransport } from \"@modelcontextprotocol/sdk/server/sse.js\";\nimport {\n  type IncomingHttpHeaders,\n  IncomingMessage,\n  type ServerResponse,\n} from \"node:http\";\nimport { createClient } from \"redis\";\nimport { Socket } from \"node:net\";\nimport { Readable } from \"node:stream\";\nimport { WebStandardStreamableHTTPServerTransport } from \"@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js\";\nimport type { BodyType } from \"./server-response-adapter\";\nimport assert from \"node:assert\";\nimport type {\n  McpEvent,\n} from \"../lib/log-helper\";\nimport { EventEmittingResponse } from \"../lib/event-emitter.js\";\nimport { AuthInfo } from \"@modelcontextprotocol/sdk/server/auth/types\";\nimport { getAuthContext } from \"../auth/auth-context\";\nimport { ServerOptions } from \".\";\n\ninterface SerializedRequest {\n  requestId: string;\n  url: string;\n  method: string;\n  body: BodyType;\n  headers: IncomingHttpHeaders;\n  auth?: AuthInfo;\n}\n\ntype LogLevel = \"log\" | \"error\" | \"warn\" | \"info\" | \"debug\";\n\ntype Logger = {\n  log: (...args: unknown[]) => void;\n  error: (...args: unknown[]) => void;\n  warn: (...args: unknown[]) => void;\n  info: (...args: unknown[]) => void;\n  debug: (...args: unknown[]) => void;\n};\n\nfunction createLogger(verboseLogs = false): Logger {\n  return {\n    log: (...args: unknown[]) => {\n      if (verboseLogs) console.log(...args);\n    },\n    error: (...args: unknown[]) => {\n      if (verboseLogs) console.error(...args);\n    },\n    warn: (...args: unknown[]) => {\n      if (verboseLogs) console.warn(...args);\n    },\n    info: (...args: unknown[]) => {\n      if (verboseLogs) console.info(...args);\n    },\n    debug: (...args: unknown[]) => {\n      if (verboseLogs) console.debug(...args);\n    },\n  };\n}\n/**\n * Configuration for the MCP handler.\n * @property redisUrl - The URL of the Redis instance to use for the MCP handler.\n * @property streamableHttpEndpoint - The endpoint to use for the streamable HTTP transport.\n * @property sseEndpoint - The endpoint to use for the SSE transport.\n * @property verboseLogs - If true, enables console logging.\n */\nexport type Config = {\n  /**\n   * The URL of the Redis instance to use for the MCP handler.\n   * @default process.env.REDIS_URL || process.env.KV_URL\n   */\n  redisUrl?: string;\n  /**\n   * The endpoint to use for the streamable HTTP transport.\n   * @deprecated Use `set basePath` instead.\n   * @default \"/mcp\"\n   */\n  streamableHttpEndpoint?: string;\n  /**\n   * The endpoint to use for the SSE transport.\n   * @deprecated Use `set basePath` instead.\n   * @default \"/sse\"\n   */\n  sseEndpoint?: string;\n  /**\n   * The endpoint to use for the SSE messages transport.\n   * @deprecated Use `set basePath` instead.\n   * @default \"/message\"\n   */\n  sseMessageEndpoint?: string;\n  /**\n   * The maximum duration of an MCP request in seconds.\n   * @default 60\n   */\n  maxDuration?: number;\n  /**\n   * If true, enables console logging.\n   * @default false\n   */\n  verboseLogs?: boolean;\n  /**\n   * The base path to use for deriving endpoints.\n   * If provided, endpoints will be derived from this path.\n   * For example, if basePath is \"/\", that means your routing is:\n   *  /app/[transport]/route.ts and then:\n   * - streamableHttpEndpoint will be \"/mcp\"\n   * - sseEndpoint will be \"/sse\"\n   * - sseMessageEndpoint will be \"/message\"\n   * @default \"\"\n   */\n  basePath?: string;\n  /**\n   * Callback function that receives MCP events.\n   * This can be used to track analytics, debug issues, or implement custom behaviors.\n   */\n  onEvent?: (event: McpEvent) => void;\n\n  /**\n   * If true, disables the SSE endpoint.\n   * As of 2025-03-26, SSE is not supported by the MCP spec.\n   * https://modelcontextprotocol.io/specification/2025-03-26/basic/transports\n   * @default false\n   */\n  disableSse?: boolean;\n\n  /**\n   * sessionIdGenerator for the streamable HTTP transport\n   */\n  sessionIdGenerator?: undefined;\n};\n\n/**\n * Derives MCP endpoints from a base path.\n * @param basePath - The base path to derive endpoints from\n * @returns An object containing the derived endpoints\n */\nfunction deriveEndpointsFromBasePath(basePath: string): {\n  streamableHttpEndpoint: string;\n  sseEndpoint: string;\n  sseMessageEndpoint: string;\n} {\n  // Remove trailing slash if present\n  const normalizedBasePath = basePath.replace(/\\/$/, \"\");\n\n  return {\n    streamableHttpEndpoint: `${normalizedBasePath}/mcp`,\n    sseEndpoint: `${normalizedBasePath}/sse`,\n    sseMessageEndpoint: `${normalizedBasePath}/message`,\n  };\n}\n/**\n * Calculates the endpoints for the MCP handler.\n * @param config - The configuration for the MCP handler.\n * @returns An object containing the endpoints for the MCP handler.\n */\nexport function calculateEndpoints({\n  basePath,\n  streamableHttpEndpoint = \"/mcp\",\n  sseEndpoint = \"/sse\",\n  sseMessageEndpoint = \"/message\",\n}: Config) {\n  const {\n    streamableHttpEndpoint: fullStreamableHttpEndpoint,\n    sseEndpoint: fullSseEndpoint,\n    sseMessageEndpoint: fullSseMessageEndpoint,\n  } = basePath != null\n    ? deriveEndpointsFromBasePath(basePath)\n    : {\n        streamableHttpEndpoint,\n        sseEndpoint,\n        sseMessageEndpoint,\n      };\n\n  return {\n    streamableHttpEndpoint: fullStreamableHttpEndpoint,\n    sseEndpoint: fullSseEndpoint,\n    sseMessageEndpoint: fullSseMessageEndpoint,\n  };\n}\n\nlet redisPublisher: ReturnType<typeof createClient>;\nlet redis: ReturnType<typeof createClient>;\n\n// WeakMap to track server metadata without preventing GC\nconst serverMetadata = new WeakMap<McpServer, {\n  sessionId: string;\n  createdAt: Date;\n  transport: SSEServerTransport;\n}>();\n\n// Periodic cleanup interval\nlet cleanupInterval: NodeJS.Timeout | null = null;\n\nasync function initializeRedis({\n  redisUrl,\n  logger,\n}: {\n  redisUrl?: string;\n  logger: Logger;\n}) {\n  if (redis && redisPublisher) {\n    return { redis, redisPublisher };\n  }\n\n  if (!redisUrl) {\n    throw new Error(\"redisUrl is required\");\n  }\n\n  redis = createClient({\n    url: redisUrl,\n  });\n  redisPublisher = createClient({\n    url: redisUrl,\n  });\n  redis.on(\"error\", (err) => {\n    logger.error(\"Redis error\", err);\n  });\n  redisPublisher.on(\"error\", (err) => {\n    logger.error(\"Redis error\", err);\n  });\n\n  await Promise.all([redis.connect(), redisPublisher.connect()]);\n\n  return { redis, redisPublisher };\n}\n\nexport function initializeMcpApiHandler(\n  initializeServer:\n    | ((server: McpServer) => Promise<void>)\n    | ((server: McpServer) => void),\n  serverOptions: ServerOptions = {},\n  config: Config = {\n    redisUrl: process.env.REDIS_URL || process.env.KV_URL,\n    streamableHttpEndpoint: \"/mcp\",\n    sseEndpoint: \"/sse\",\n    sseMessageEndpoint: \"/message\",\n    basePath: \"\",\n    maxDuration: 60,\n    verboseLogs: false,\n    disableSse: false,\n  }\n) {\n  const {\n    redisUrl,\n    basePath,\n    streamableHttpEndpoint: explicitStreamableHttpEndpoint,\n    sseEndpoint: explicitSseEndpoint,\n    sseMessageEndpoint: explicitSseMessageEndpoint,\n    maxDuration,\n    verboseLogs,\n    disableSse,\n    sessionIdGenerator,\n  } = config;\n\n  const {\n    serverInfo = {\n      name: \"mcp-typescript server on vercel\",\n      version: \"0.1.0\",\n    },\n    ...mcpServerOptions\n  } = serverOptions;\n\n  // If basePath is provided, derive endpoints from it\n  const { streamableHttpEndpoint, sseEndpoint, sseMessageEndpoint } =\n    calculateEndpoints({\n      basePath,\n      streamableHttpEndpoint: explicitStreamableHttpEndpoint,\n      sseEndpoint: explicitSseEndpoint,\n      sseMessageEndpoint: explicitSseMessageEndpoint,\n    });\n\n  const logger = createLogger(verboseLogs);\n\n  let servers: McpServer[] = [];\n\n  // Note: In SDK 1.26.0+, stateless transports cannot be reused across requests.\n  // We create a fresh transport and server per POST request.\n  \n  // Start periodic cleanup if not already running\n  if (!cleanupInterval) {\n    cleanupInterval = setInterval(() => {\n      const now = Date.now();\n      const staleThreshold = 5 * 60 * 1000; // 5 minutes\n      \n      servers = servers.filter(server => {\n        const metadata = serverMetadata.get(server);\n        if (!metadata) {\n          // No metadata means the server is orphaned\n          logger.log(\"Removing orphaned server without metadata\");\n          try {\n            if (server?.server) {\n              server.server.close();\n            }\n          } catch (error) {\n            logger.error(\"Error closing orphaned server:\", error);\n          }\n          return false;\n        }\n        \n        const age = now - metadata.createdAt.getTime();\n        if (age > staleThreshold) {\n          logger.log(`Removing stale server (session ${metadata.sessionId}, age: ${age}ms)`);\n          try {\n            if (server?.server) {\n              server.server.close();\n            }\n            if (metadata.transport?.close) {\n              metadata.transport.close();\n            }\n          } catch (error) {\n            logger.error(\"Error closing stale server:\", error);\n          }\n          serverMetadata.delete(server);\n          return false;\n        }\n        \n        return true;\n      });\n    }, 30 * 1000); // Run every 30 seconds\n  }\n\n  return async function mcpApiHandler(req: Request, res: ServerResponse) {\n    const url = new URL(req.url || \"\", \"https://example.com\");\n    if (url.pathname === streamableHttpEndpoint) {\n      if (req.method === \"GET\") {\n        logger.log(\"Received GET MCP request\");\n        res.writeHead(405).end(\n          JSON.stringify({\n            jsonrpc: \"2.0\",\n            error: {\n              code: -32000,\n              message: \"Method not allowed.\",\n            },\n            id: null,\n          })\n        );\n        return;\n      }\n      if (req.method === \"DELETE\") {\n        logger.log(\"Received DELETE MCP request\");\n        res.writeHead(405).end(\n          JSON.stringify({\n            jsonrpc: \"2.0\",\n            error: {\n              code: -32000,\n              message: \"Method not allowed.\",\n            },\n            id: null,\n          })\n        );\n        return;\n      }\n\n      if (req.method === \"POST\") {\n        const eventRes = new EventEmittingResponse(\n          createFakeIncomingMessage(),\n          config.onEvent\n        );\n\n        // Parse the request body\n        let bodyContent: BodyType;\n        const contentType = req.headers.get(\"content-type\") || \"\";\n        if (contentType.includes(\"application/json\")) {\n          bodyContent = await req.json();\n        } else {\n          bodyContent = await req.text();\n        }\n\n        // In SDK 1.26.0+, stateless transports cannot be reused across requests.\n        // Create a fresh transport and server per POST request and use the\n        // WebStandard transport directly since we already have a Web Request.\n        const transport = new WebStandardStreamableHTTPServerTransport({\n          sessionIdGenerator: sessionIdGenerator,\n        });\n        const server = new McpServer(serverInfo, mcpServerOptions);\n        await initializeServer(server);\n        await server.connect(transport);\n\n        try {\n          // Build a new Request with the already-parsed body so the transport\n          // doesn't try to consume the (already-read) body stream again.\n          const webReq = new Request(req.url, {\n            method: req.method,\n            headers: req.headers,\n            body: JSON.stringify(bodyContent),\n          });\n          // Propagate auth info for downstream tool handlers\n          (webReq as any).auth = req.auth;\n\n          const webResp = await transport.handleRequest(webReq, {\n            authInfo: req.auth,\n          });\n\n          // Write the response back through the ServerResponse adapter\n          res.writeHead(webResp.status, Object.fromEntries(webResp.headers));\n          if (webResp.body) {\n            const reader = webResp.body.getReader();\n            try {\n              while (true) {\n                const { done, value } = await reader.read();\n                if (done) break;\n                res.write(value);\n              }\n            } finally {\n              reader.releaseLock();\n            }\n          }\n          res.end();\n\n          if (\n            typeof bodyContent === \"object\" &&\n            bodyContent &&\n            \"method\" in bodyContent\n          ) {\n            eventRes.requestCompleted(\n              bodyContent.method as string,\n              bodyContent\n            );\n          }\n        } catch (error) {\n          if (\n            typeof bodyContent === \"object\" &&\n            bodyContent &&\n            \"method\" in bodyContent\n          ) {\n            eventRes.requestCompleted(\n              bodyContent.method as string,\n              undefined,\n              error instanceof Error ? error : String(error)\n            );\n          }\n          throw error;\n        }\n      }\n    } else if (url.pathname === sseEndpoint) {\n      if (disableSse) {\n        res.statusCode = 404;\n        res.end(\"Not found\");\n        return;\n      }\n\n      // Check HTTP method - only allow GET for SSE connections\n      if (req.method !== \"GET\") {\n        logger.log(`Rejected SSE connection with method ${req.method}`);\n        res\n          .writeHead(405, { \"Content-Type\": \"text/plain\" })\n          .end(\"Method Not Allowed\");\n        return;\n      }\n\n      // Check that Accept header supports event-stream\n      const acceptHeader =\n        req.headers.get(\"accept\") || req.headers.get(\"Accept\");\n      if (\n        acceptHeader &&\n        !acceptHeader.includes(\"text/event-stream\") &&\n        !acceptHeader.includes(\"*/*\") &&\n        !acceptHeader.includes(\"text/*\")\n      ) {\n        logger.log(\n          `Rejected SSE connection with incompatible Accept header: ${acceptHeader}`\n        );\n        res\n          .writeHead(406, { \"Content-Type\": \"text/plain\" })\n          .end(\"Not Acceptable\");\n        return;\n      }\n\n      const { redis, redisPublisher } = await initializeRedis({\n        redisUrl,\n        logger,\n      });\n      logger.log(\"Got new SSE connection\");\n      assert(sseMessageEndpoint, \"sseMessageEndpoint is required\");\n      const transport = new SSEServerTransport(sseMessageEndpoint, res);\n      const sessionId = transport.sessionId;\n\n      const eventRes = new EventEmittingResponse(\n        createFakeIncomingMessage(),\n        config.onEvent,\n        sessionId\n      );\n      eventRes.startSession(\"SSE\", {\n        userAgent: req.headers.get(\"user-agent\") ?? undefined,\n        ip:\n          req.headers.get(\"x-forwarded-for\") ??\n          req.headers.get(\"x-real-ip\") ??\n          undefined,\n      });\n\n      const server = new McpServer(serverInfo, serverOptions);\n      \n      // Track cleanup state to prevent double cleanup\n      let isCleanedUp = false;\n      let interval: NodeJS.Timeout | null = null;\n      let timeout: NodeJS.Timeout | null = null;\n      let abortHandler: (() => void) | null = null;\n      let handleMessage: ((message: string) => Promise<void>) | null = null;\n      let logs: { type: LogLevel; messages: string[]; }[] = [];\n      \n      // Comprehensive cleanup function\n      const cleanup = async (reason: string) => {\n        if (isCleanedUp) return;\n        isCleanedUp = true;\n        \n        logger.log(`Cleaning up SSE connection: ${reason}`);\n        \n        // Clear timers\n        if (timeout) {\n          clearTimeout(timeout);\n          timeout = null;\n        }\n        if (interval) {\n          clearInterval(interval);\n          interval = null;\n        }\n        \n        // Remove abort event listener\n        if (abortHandler) {\n          req.signal.removeEventListener(\"abort\", abortHandler);\n          abortHandler = null;\n        }\n        \n        // Unsubscribe from Redis\n        if (handleMessage) {\n          try {\n            await redis.unsubscribe(`requests:${sessionId}`, handleMessage);\n            logger.log(`Unsubscribed from requests:${sessionId}`);\n          } catch (error) {\n            logger.error(\"Error unsubscribing from Redis:\", error);\n          }\n        }\n        \n        // Close server and transport\n        try {\n          if (server?.server) {\n            await server.server.close();\n          }\n          if (transport?.close) {\n            await transport.close();\n          }\n        } catch (error) {\n          logger.error(\"Error closing server/transport:\", error);\n        }\n        \n        // Remove server from array and WeakMap\n        servers = servers.filter((s) => s !== server);\n        serverMetadata.delete(server);\n        \n        // End session event\n        eventRes.endSession(\"SSE\");\n        \n        // Clear logs array to free memory\n        logs = [];\n        \n        // End response if not already ended\n        if (!res.headersSent) {\n          res.statusCode = 200;\n          res.end();\n        }\n      };\n      \n      try {\n        await initializeServer(server);\n        servers.push(server);\n        \n        // Store metadata in WeakMap\n        serverMetadata.set(server, {\n          sessionId,\n          createdAt: new Date(),\n          transport\n        });\n\n        server.server.onclose = () => {\n          cleanup(\"server closed\");\n        };\n\n        // eslint-disable-next-line no-inner-declarations\n        function logInContext(severity: LogLevel, ...messages: string[]) {\n          logs.push({\n            type: severity,\n            messages,\n          });\n        }\n\n        // Handles messages originally received via /message\n        handleMessage = async (message: string) => {\n          logger.log(\"Received message from Redis\", message);\n          logInContext(\"log\", \"Received message from Redis\", message);\n          const request = JSON.parse(message) as SerializedRequest;\n\n          // Make in IncomingMessage object because that is what the SDK expects.\n          // Pass auth from the serialized request to preserve the caller's auth context\n          const req = createFakeIncomingMessage({\n            method: request.method,\n            url: request.url,\n            headers: request.headers,\n            body: request.body,\n            auth: request.auth,\n          });\n\n          const syntheticRes = new EventEmittingResponse(\n            req,\n            config.onEvent,\n            sessionId\n          );\n          let status = 100;\n          let body = \"\";\n          syntheticRes.writeHead = (statusCode: number) => {\n            status = statusCode;\n            return syntheticRes;\n          };\n          syntheticRes.end = (b: unknown) => {\n            body = b as string;\n            return syntheticRes;\n          };\n\n          try {\n            await transport.handlePostMessage(req, syntheticRes);\n\n            // If it was a function call, complete it\n            if (\n              typeof request.body === \"object\" &&\n              request.body &&\n              \"method\" in request.body\n            ) {\n              try {\n                const result = JSON.parse(body);\n                eventRes.requestCompleted(request.body.method as string, result);\n              } catch {\n                eventRes.requestCompleted(request.body.method as string, body);\n              }\n            }\n          } catch (error) {\n            eventRes.error(\n              error instanceof Error ? error : String(error),\n              \"Error handling SSE message\",\n              \"session\"\n            );\n            throw error;\n          }\n\n          await redisPublisher.publish(\n            `responses:${sessionId}:${request.requestId}`,\n            JSON.stringify({\n              status,\n              body,\n            })\n          );\n\n          if (status >= 200 && status < 300) {\n            logInContext(\n              \"log\",\n              `Request ${sessionId}:${request.requestId} succeeded: ${body}`\n            );\n          } else {\n            logInContext(\n              \"error\",\n              `Message for ${sessionId}:${request.requestId} failed with status ${status}: ${body}`\n            );\n            eventRes.error(\n              `Request failed with status ${status}`,\n              body,\n              \"session\"\n            );\n          }\n        };\n\n        interval = setInterval(() => {\n          for (const log of logs) {\n            logger[log.type](...log.messages);\n          }\n          logs = [];\n        }, 100);\n\n        await redis.subscribe(`requests:${sessionId}`, handleMessage);\n        logger.log(`Subscribed to requests:${sessionId}`);\n\n        let resolveTimeout: (value: unknown) => void;\n        const waitPromise = new Promise((resolve) => {\n          resolveTimeout = resolve;\n          timeout = setTimeout(() => {\n            resolve(\"max duration reached\");\n          }, (maxDuration ?? 60) * 1000);\n        });\n\n        abortHandler = () => resolveTimeout(\"client hang up\");\n        req.signal.addEventListener(\"abort\", abortHandler);\n        \n        // Handle response close event\n        res.on(\"close\", () => {\n          cleanup(\"response closed\");\n        });\n        \n        // Handle response error event\n        res.on(\"error\", (error) => {\n          logger.error(\"Response error:\", error);\n          cleanup(\"response error\");\n        });\n\n        await server.connect(transport);\n        const closeReason = await waitPromise;\n        logger.log(closeReason);\n        await cleanup(String(closeReason));\n      } catch (error) {\n        logger.error(\"Error in SSE handler:\", error);\n        await cleanup(\"error during setup\");\n        throw error;\n      }\n    } else if (url.pathname === sseMessageEndpoint) {\n      if (disableSse) {\n        res.statusCode = 404;\n        res.end(\"Not found\");\n        return;\n      }\n\n      const { redis, redisPublisher } = await initializeRedis({\n        redisUrl,\n        logger,\n      });\n      logger.log(\"Received message\");\n\n      const body = await req.text();\n      let parsedBody: BodyType;\n      try {\n        parsedBody = JSON.parse(body);\n      } catch (e) {\n        parsedBody = body;\n      }\n\n      const sessionId = url.searchParams.get(\"sessionId\") || \"\";\n      if (!sessionId) {\n        res.statusCode = 400;\n        res.end(\"No sessionId provided\");\n        return;\n      }\n      const requestId = crypto.randomUUID();\n      const serializedRequest: SerializedRequest = {\n        requestId,\n        url: req.url || \"\",\n        method: req.method || \"\",\n        body: parsedBody,\n        headers: Object.fromEntries(req.headers.entries()),\n        auth: req.auth,\n      };\n\n      // Declare timeout and response handling state before subscription\n      let timeout: NodeJS.Timeout | null = null;\n      let hasResponded = false;\n      let isCleanedUp = false;\n      \n      // Cleanup function to ensure all resources are freed\n      const cleanup = async () => {\n        if (isCleanedUp) return;\n        isCleanedUp = true;\n        \n        if (timeout) {\n          clearTimeout(timeout);\n          timeout = null;\n        }\n        \n        try {\n          await redis.unsubscribe(`responses:${sessionId}:${requestId}`);\n        } catch (error) {\n          logger.error(\"Error unsubscribing from Redis response channel:\", error);\n        }\n      };\n      \n      // Safe response handler to prevent double res.end()\n      const sendResponse = async (status: number, body: string) => {\n        if (!hasResponded) {\n          hasResponded = true;\n          res.statusCode = status;\n          res.end(body);\n          await cleanup();\n        }\n      };\n      \n      // Response handler\n      const handleResponse = async (message: string) => {\n        try {\n          const response = JSON.parse(message) as {\n            status: number;\n            body: string;\n          };\n          await sendResponse(response.status, response.body);\n        } catch (error) {\n          logger.error(\"Failed to parse response message:\", error);\n          await sendResponse(500, \"Internal server error\");\n        }\n      };\n\n      try {\n        // Handles responses from the /sse endpoint.\n        await redis.subscribe(\n          `responses:${sessionId}:${requestId}`,\n          handleResponse\n        );\n\n        // Queue the request in Redis so that a subscriber can pick it up.\n        // One queue per session.\n        await redisPublisher.publish(\n          `requests:${sessionId}`,\n          JSON.stringify(serializedRequest)\n        );\n        logger.log(`Published requests:${sessionId}`, serializedRequest);\n\n        // Set timeout after subscription is established\n        timeout = setTimeout(async () => {\n          await sendResponse(408, \"Request timed out\");\n        }, 10 * 1000);\n\n        // Handle response close event\n        res.on(\"close\", async () => {\n          if (!hasResponded) {\n            hasResponded = true;\n            await cleanup();\n          }\n        });\n        \n        // Handle response error event\n        res.on(\"error\", async (error) => {\n          logger.error(\"Response error in message handler:\", error);\n          if (!hasResponded) {\n            hasResponded = true;\n            await cleanup();\n          }\n        });\n      } catch (error) {\n        logger.error(\"Error in message handler:\", error);\n        await cleanup();\n        if (!hasResponded) {\n          res.statusCode = 500;\n          res.end(\"Internal server error\");\n        }\n      }\n    } else {\n      res.statusCode = 404;\n      res.end(\"Not found\");\n    }\n  };\n}\n\n// Define the options interface\ninterface FakeIncomingMessageOptions {\n  method?: string;\n  url?: string;\n  headers?: IncomingHttpHeaders;\n  body?: BodyType;\n  socket?: Socket;\n  auth?: AuthInfo;\n}\n\n// Create a fake IncomingMessage\nfunction createFakeIncomingMessage(\n  options: FakeIncomingMessageOptions = {}\n): IncomingMessage & { auth?: AuthInfo } {\n  const {\n    method = \"GET\",\n    url = \"/\",\n    headers = {},\n    body = null,\n    socket = new Socket(),\n  } = options;\n\n  // Create a readable stream that will be used as the base for IncomingMessage\n  const readable = new Readable();\n  readable._read = (): void => {}; // Required implementation\n\n  // Add the body content if provided\n  if (body) {\n    if (typeof body === \"string\") {\n      readable.push(body);\n    } else if (Buffer.isBuffer(body)) {\n      readable.push(body);\n    } else {\n      // Ensure proper JSON-RPC format\n      const bodyString = JSON.stringify(body);\n      readable.push(bodyString);\n    }\n    readable.push(null); // Signal the end of the stream\n  } else {\n    readable.push(null); // Always end the stream even if no body\n  }\n\n  // Create the IncomingMessage instance\n  const req = new IncomingMessage(socket) as IncomingMessage & {\n    auth?: AuthInfo;\n  };\n\n  // Set the properties\n  req.method = method;\n  req.url = url;\n  req.headers = headers;\n  req.rawHeaders = Object.entries(headers).flatMap(([key, value]) => \n    Array.isArray(value) \n      ? value.flatMap(v => [key, v]) \n      : [key, value ?? \"\"]\n  );\n\n  const auth = options.auth || getAuthContext();\n  if (auth) {\n    // See https://github.com/modelcontextprotocol/typescript-sdk/blob/590d4841373fc4eb86ecc9079834353a98cb84a3/src/server/auth/middleware/bearerAuth.ts#L71 for more info.\n    (req as { auth?: AuthInfo }).auth = auth;\n  }\n\n  // Copy over the stream methods\n  req.push = readable.push.bind(readable);\n  req.read = readable.read.bind(readable);\n  // @ts-expect-error\n  req.on = readable.on.bind(readable);\n  req.pipe = readable.pipe.bind(readable);\n\n  return req;\n}\n","import { ServerResponse, type IncomingMessage } from \"node:http\";\nimport {\n  type McpErrorEvent,\n  type McpEvent,\n  type McpRequestEvent,\n  type McpSessionEvent,\n  createEvent,\n} from \"./log-helper\";\n\nexport class EventEmittingResponse extends ServerResponse {\n  private onEvent?: (event: McpEvent) => void;\n  private sessionId?: string;\n  private requestId: string;\n  private startTime: number;\n\n  constructor(\n    req: IncomingMessage,\n    onEvent?: (event: McpEvent) => void,\n    sessionId?: string\n  ) {\n    super(req);\n    this.onEvent = onEvent;\n    this.sessionId = sessionId;\n    this.requestId = crypto.randomUUID();\n    this.startTime = Date.now();\n  }\n\n  emitEvent(event: Omit<McpEvent, \"timestamp\" | \"sessionId\" | \"requestId\">) {\n    if (this.onEvent) {\n      this.onEvent(\n        createEvent({\n          ...event,\n          sessionId: this.sessionId,\n          requestId: this.requestId,\n        } as Omit<McpEvent, \"timestamp\">)\n      );\n    }\n  }\n\n  startSession(\n    transport: \"SSE\" | \"HTTP\",\n    clientInfo?: { userAgent?: string; ip?: string }\n  ) {\n    this.emitEvent({\n      type: \"SESSION_STARTED\",\n      transport,\n      clientInfo,\n    } as Omit<McpSessionEvent, \"timestamp\" | \"sessionId\" | \"requestId\">);\n  }\n\n  endSession(transport: \"SSE\" | \"HTTP\") {\n    this.emitEvent({\n      type: \"SESSION_ENDED\",\n      transport,\n    } as Omit<McpSessionEvent, \"timestamp\" | \"sessionId\" | \"requestId\">);\n  }\n\n  requestReceived(method: string, parameters?: unknown) {\n    this.emitEvent({\n      type: \"REQUEST_RECEIVED\",\n      method,\n      parameters,\n      status: \"success\",\n    } as Omit<McpRequestEvent, \"timestamp\" | \"sessionId\" | \"requestId\">);\n  }\n\n  requestCompleted(method: string, result?: unknown, error?: Error | string) {\n    this.emitEvent({\n      type: \"REQUEST_COMPLETED\",\n      method,\n      result,\n      duration: Date.now() - this.startTime,\n      status: error ? \"error\" : \"success\",\n    } as Omit<McpRequestEvent, \"timestamp\" | \"sessionId\" | \"requestId\">);\n\n    if (error) {\n      this.error(error, `Error executing request ${method}`, \"request\");\n    }\n  }\n\n  error(\n    error: Error | string,\n    context?: string,\n    source: McpErrorEvent[\"source\"] = \"system\",\n    severity: McpErrorEvent[\"severity\"] = \"error\"\n  ) {\n    this.emitEvent({\n      type: \"ERROR\",\n      error,\n      context,\n      source,\n      severity,\n    } as Omit<McpErrorEvent, \"timestamp\" | \"sessionId\" | \"requestId\">);\n  }\n\n  end(\n    chunk?: unknown,\n    encoding?: BufferEncoding | (() => void),\n    cb?: () => void\n  ): this {\n    let finalChunk = chunk;\n    let finalEncoding = encoding;\n    let finalCallback = cb;\n\n    if (typeof chunk === \"function\") {\n      finalCallback = chunk as () => void;\n      finalChunk = undefined;\n      finalEncoding = undefined;\n    } else if (typeof encoding === \"function\") {\n      finalCallback = encoding as () => void;\n      finalEncoding = undefined;\n    }\n\n    return super.end(\n      finalChunk as string | Buffer,\n      finalEncoding as BufferEncoding,\n      finalCallback\n    );\n  }\n}\n","export type McpEventType =\n  | \"SESSION_STARTED\" // When a new client session begins (either HTTP or SSE)\n  | \"SESSION_ENDED\" // When a client session ends (SSE disconnection)\n  | \"REQUEST_RECEIVED\" // When a request is received from the client\n  | \"REQUEST_COMPLETED\" // When a request completes\n  | \"ERROR\"; // When an error occurs during any operation\n\nexport interface McpEventBase {\n  type: McpEventType;\n  timestamp: number;\n  sessionId?: string;\n  requestId?: string; // To track individual requests within a session\n}\n\nexport interface McpSessionEvent extends McpEventBase {\n  type: \"SESSION_STARTED\" | \"SESSION_ENDED\";\n  transport: \"SSE\" | \"HTTP\";\n  clientInfo?: {\n    userAgent?: string;\n    ip?: string;\n  };\n}\n\nexport interface McpRequestEvent extends McpEventBase {\n  type: \"REQUEST_RECEIVED\" | \"REQUEST_COMPLETED\";\n  method: string;\n  parameters?: unknown;\n  result?: unknown;\n  duration?: number; // For REQUEST_COMPLETED events\n  status: \"success\" | \"error\";\n}\n\nexport interface McpErrorEvent extends McpEventBase {\n  type: \"ERROR\";\n  error: Error | string;\n  context?: string;\n  source: \"request\" | \"session\" | \"system\";\n  severity: \"warning\" | \"error\" | \"fatal\";\n}\n\nexport type McpEvent = McpSessionEvent | McpRequestEvent | McpErrorEvent;\n\nexport function createEvent<T extends McpEvent>(\n  event: Omit<T, \"timestamp\">\n): T {\n  return {\n    ...event,\n    timestamp: Date.now(),\n  } as T;\n}\n","import { AuthInfo } from \"@modelcontextprotocol/sdk/server/auth/types.js\";\nimport { AsyncLocalStorage } from \"node:async_hooks\";\n\nconst authContext = new AsyncLocalStorage<AuthInfo>();\n\nexport function getAuthContext(): AuthInfo | undefined {\n  return authContext.getStore();\n}\n\nexport function withAuthContext<T>(authInfo: AuthInfo, callback: () => T): T {\n  return authContext.run(authInfo, callback);\n}\n","import { EventEmitter } from 'node:events';\nimport type { ServerResponse } from 'node:http';\n\ntype WriteheadArgs = {\n  statusCode: number;\n  headers?: Record<string, string>;\n};\n\n// biome-ignore lint/suspicious/noExplicitAny: Not deterministic\nexport type BodyType = string | Buffer | Record<string, any> | null;\n\ntype EventListener = (...args: unknown[]) => void;\n\n/**\n * Anthropic's MCP API requires a server response object. This function\n * creates a fake server response object that can be used to pass to the MCP API.\n */\nexport function createServerResponseAdapter(\n  signal: AbortSignal,\n  fn: (re: ServerResponse) => Promise<void> | void\n): Promise<Response> {\n  let writeHeadResolver: (v: WriteheadArgs) => void;\n  const writeHeadPromise = new Promise<WriteheadArgs>(resolve => {\n    writeHeadResolver = resolve;\n  });\n\n  return new Promise(resolve => {\n    let controller: ReadableStreamController<Uint8Array> | undefined;\n    let shouldClose = false;\n    let wroteHead = false;\n    let statusCode = 200;\n    let headers: Record<string, string> | undefined;\n\n    const writeHead = (code: number, headersArg?: Record<string, string>) => {\n      if (typeof headersArg === 'string') {\n        throw new Error('Status message of writeHead not supported');\n      }\n      statusCode = code;\n      headers = headersArg;\n      wroteHead = true;\n      writeHeadResolver({\n        statusCode,\n        headers,\n      });\n      return fakeServerResponse;\n    };\n\n    const bufferedData: Uint8Array[] = [];\n\n    const write = (\n      chunk: Buffer | string | Uint8Array,\n      encoding?: BufferEncoding\n    ): boolean => {\n      if (encoding) {\n        throw new Error('Encoding not supported');\n      }\n      if (chunk instanceof Buffer) {\n        throw new Error('Buffer not supported');\n      }\n\n      // SDK 1.25+ uses Hono which sends Uint8Array (already encoded)\n      // SDK 1.24- sends strings that need encoding\n      let data: Uint8Array;\n      if (chunk instanceof Uint8Array) {\n        data = chunk;\n      } else if (typeof chunk === 'string') {\n        data = new TextEncoder().encode(chunk);\n      } else {\n        throw new Error('Unexpected chunk type: ' + typeof chunk);\n      }\n\n      if (!wroteHead) {\n        writeHead(statusCode, headers);\n      }\n      if (!controller) {\n        bufferedData.push(data);\n        return true;\n      }\n      controller.enqueue(data);\n      return true;\n    };\n\n    const eventEmitter = new EventEmitter();\n\n    const fakeServerResponse = {\n      writeHead,\n      write,\n      end: (data?: Buffer | string) => {\n        if (data) {\n          write(data);\n        }\n\n        if (!controller) {\n          shouldClose = true;\n          return fakeServerResponse;\n        }\n        try {\n          controller.close();\n        } catch {\n          /* May be closed on tcp layer */\n        }\n        return fakeServerResponse;\n      },\n      on: (event: string, listener: EventListener) => {\n        eventEmitter.on(event, listener);\n        return fakeServerResponse;\n      },\n      get statusCode() {\n        return statusCode;\n      },\n      set statusCode(code: number) {\n        statusCode = code;\n\n        // If the status code is set after writeHead, we need to call\n        // writeHead again to update the status code.\n        if (wroteHead) {\n          writeHeadResolver({\n            statusCode,\n            headers,\n          });\n        }\n      },\n    };\n\n    signal.addEventListener('abort', () => {\n      eventEmitter.emit('close');\n    });\n\n    void fn(fakeServerResponse as ServerResponse);\n\n    void (async () => {\n      const head = await writeHeadPromise;\n\n      const response = new Response(\n        new ReadableStream({\n          start(c) {\n            controller = c;\n            for (const chunk of bufferedData) {\n              controller.enqueue(chunk);\n            }\n            if (shouldClose) {\n              controller.close();\n            }\n          },\n        }),\n        {\n          status: head.statusCode,\n          headers: head.headers,\n        }\n      );\n\n      resolve(response);\n    })();\n  });\n}\n","import { type Config, initializeMcpApiHandler } from \"./mcp-api-handler\";\nimport { createServerResponseAdapter } from \"./server-response-adapter\";\nimport type { ServerOptions as McpServerOptions } from \"@modelcontextprotocol/sdk/server/index.js\";\nimport type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\n\n/**\n * Creates a MCP handler that can be used to handle MCP requests.\n * @param initializeServer - A function that initializes the MCP server. Use this to access the server instance and register tools, prompts, and resources.\n * @param serverOptions - Options for the MCP server.\n * @param config - Configuration for the MCP handler.\n * @returns A function that can be used to handle MCP requests.\n */\n\nexport type ServerOptions = McpServerOptions & {\n  serverInfo?: {\n    name: string;\n    version: string;\n  };\n};\n\nexport default function createMcpRouteHandler(\n  initializeServer:\n    | ((server: McpServer) => Promise<void>)\n    | ((server: McpServer) => void),\n  serverOptions?: ServerOptions,\n  config?: Config\n): (request: Request) => Promise<Response> {\n  const mcpHandler = initializeMcpApiHandler(\n    initializeServer,\n    serverOptions,\n    config\n  );\n  return (request: Request) => {\n    return createServerResponseAdapter(request.signal, (res) => {\n      mcpHandler(request, res);\n    });\n  };\n}\n","import {AuthInfo} from \"@modelcontextprotocol/sdk/server/auth/types.js\";\nimport {\n  InvalidTokenError,\n  InsufficientScopeError,\n  ServerError,\n} from \"@modelcontextprotocol/sdk/server/auth/errors.js\";\nimport {withAuthContext} from \"./auth-context\";\nimport {getPublicOrigin} from \"../lib/url\";\n\ndeclare global {\n  interface Request {\n    auth?: AuthInfo;\n  }\n}\n\nexport function withMcpAuth(\n  handler: (req: Request) => Response | Promise<Response>,\n  verifyToken: (\n    req: Request,\n    bearerToken?: string\n  ) => AuthInfo | undefined | Promise<AuthInfo | undefined>,\n  {\n    required = false,\n    resourceMetadataPath = \"/.well-known/oauth-protected-resource\",\n    requiredScopes,\n    resourceUrl,\n  }: {\n    required?: boolean;\n    resourceMetadataPath?: string;\n    requiredScopes?: string[];\n    /**\n     * Explicit resource URL override. When provided, this URL is used as the\n     * origin for constructing the resource_metadata URL. Use this when running\n     * behind a proxy that doesn't set standard forwarding headers, or when you\n     * need to specify a specific public URL.\n     *\n     * If not provided, the origin is automatically detected from proxy headers\n     * (X-Forwarded-Host, X-Forwarded-Proto, Forwarded) or falls back to req.url.\n     */\n    resourceUrl?: string;\n  } = {}\n) {\n  return async (req: Request) => {\n    const origin = resourceUrl ?? getPublicOrigin(req);\n    const resourceMetadataUrl = `${origin}${resourceMetadataPath}`;\n\n    const authHeader = req.headers.get(\"Authorization\");\n    const [type, token] = authHeader?.split(\" \") || [];\n\n    // Only support bearer token as per the MCP spec\n    // https://modelcontextprotocol.io/specification/2025-03-26/basic/authorization#2-6-1-token-requirements\n    const bearerToken = type?.toLowerCase() === \"bearer\" ? token : undefined;\n\n    let authInfo: AuthInfo | undefined;\n    try {\n      authInfo = await verifyToken(req, bearerToken);\n    } catch (error) {\n      console.error(\"Unexpected error authenticating bearer token:\", error);\n      const publicError = new InvalidTokenError(\"Invalid token\");\n      return new Response(JSON.stringify(publicError.toResponseObject()), {\n        status: 401,\n        headers: {\n          \"WWW-Authenticate\": `Bearer error=\"${publicError.errorCode}\", error_description=\"${publicError.message}\", resource_metadata=\"${resourceMetadataUrl}\"`,\n          \"Content-Type\": \"application/json\",\n        },\n      });\n    }\n\n    try {\n      if (required && !authInfo) {\n        throw new InvalidTokenError(\"No authorization provided\");\n      }\n\n      if (!authInfo) {\n        return handler(req);\n      }\n\n      // Check if token has the required scopes (if any)\n      if (requiredScopes?.length) {\n        const hasAllScopes = requiredScopes.every((scope) =>\n          authInfo!.scopes.includes(scope)\n        );\n\n        if (!hasAllScopes) {\n          throw new InsufficientScopeError(\"Insufficient scope\");\n        }\n      }\n\n      // Check if the token is expired\n      if (authInfo.expiresAt && authInfo.expiresAt < Date.now() / 1000) {\n        throw new InvalidTokenError(\"Token has expired\");\n      }\n\n      // Set auth info on the request object after successful verification\n      req.auth = authInfo;\n\n      return withAuthContext(authInfo, () => handler(req));\n    } catch (error) {\n      if (error instanceof InvalidTokenError) {\n        return new Response(JSON.stringify(error.toResponseObject()), {\n          status: 401,\n          headers: {\n            \"WWW-Authenticate\": `Bearer error=\"${error.errorCode}\", error_description=\"${error.message}\", resource_metadata=\"${resourceMetadataUrl}\"`,\n            \"Content-Type\": \"application/json\",\n          },\n        });\n      } else if (error instanceof InsufficientScopeError) {\n        return new Response(JSON.stringify(error.toResponseObject()), {\n          status: 403,\n          headers: {\n            \"WWW-Authenticate\": `Bearer error=\"${error.errorCode}\", error_description=\"${error.message}\", resource_metadata=\"${resourceMetadataUrl}\"`,\n            \"Content-Type\": \"application/json\",\n          },\n        });\n      } else if (error instanceof ServerError) {\n        return new Response(JSON.stringify(error.toResponseObject()), {\n          status: 500,\n          headers: {\n            \"Content-Type\": \"application/json\",\n          },\n        });\n      } else {\n        console.error(\"Unexpected error authenticating bearer token:\", error);\n        const serverError = new ServerError(\"Internal Server Error\");\n        return new Response(JSON.stringify(serverError.toResponseObject()), {\n          status: 500,\n          headers: {\n            \"Content-Type\": \"application/json\",\n          },\n        });\n      }\n    }\n  };\n}\n","/**\n * Get the public-facing origin from a request, respecting proxy headers.\n *\n * When running behind a reverse proxy (e.g., nginx, Vercel, Cloudflare),\n * the `req.url` typically reflects the internal URL (e.g., http://localhost:3000).\n * This function reconstructs the public-facing origin using standard proxy headers.\n *\n * Header precedence:\n * 1. X-Forwarded-Host + X-Forwarded-Proto (most common)\n * 2. Forwarded header (RFC 7239)\n * 3. Falls back to req.url origin\n *\n * @param req - The incoming request\n * @returns The public-facing origin (e.g., \"https://example.org\")\n */\nexport function getPublicOrigin(req: Request): string {\n  const forwardedHost = req.headers.get(\"x-forwarded-host\");\n  const forwardedProto = req.headers.get(\"x-forwarded-proto\");\n\n  // If we have X-Forwarded-Host, construct origin from forwarded headers\n  if (forwardedHost) {\n    // X-Forwarded-Host can contain multiple comma-separated values; use the first (leftmost)\n    const host = forwardedHost.split(\",\")[0].trim();\n    // X-Forwarded-Proto can also be comma-separated\n    const proto = forwardedProto?.split(\",\")[0].trim() || \"https\";\n    return `${proto}://${host}`;\n  }\n\n  // Check RFC 7239 Forwarded header (less common but standardized)\n  const forwarded = req.headers.get(\"forwarded\");\n  if (forwarded) {\n    const parsed = parseForwardedHeader(forwarded);\n    if (parsed.host) {\n      const proto = parsed.proto || \"https\";\n      return `${proto}://${parsed.host}`;\n    }\n  }\n\n  // Fallback to req.url origin\n  return new URL(req.url).origin;\n}\n\n/**\n * Get the public-facing URL from a request, respecting proxy headers.\n *\n * @param req - The incoming request\n * @returns The public-facing URL with the correct origin\n */\nexport function getPublicUrl(req: Request): URL {\n  const url = new URL(req.url);\n  const publicOrigin = getPublicOrigin(req);\n\n  // Construct a new URL with the public origin but preserve pathname, search, and hash\n  const result = new URL(url.pathname + url.search + url.hash, publicOrigin);\n  return result;\n}\n\n/**\n * Parse the RFC 7239 Forwarded header.\n * Example: \"for=192.0.2.60;proto=https;host=example.com\"\n */\nfunction parseForwardedHeader(\n  forwarded: string\n): { host?: string; proto?: string } {\n  const result: { host?: string; proto?: string } = {};\n\n  // The header can contain multiple comma-separated forwarded elements; use the first\n  const firstElement = forwarded.split(\",\")[0];\n\n  // Parse key=value pairs separated by semicolons\n  const pairs = firstElement.split(\";\");\n  for (const pair of pairs) {\n    const [key, value] = pair.split(\"=\").map((s) => s.trim().toLowerCase());\n    if (key === \"host\" && value) {\n      // Remove surrounding quotes if present\n      result.host = value.replace(/^\"|\"$/g, \"\");\n    } else if (key === \"proto\" && value) {\n      result.proto = value.replace(/^\"|\"$/g, \"\");\n    }\n  }\n\n  return result;\n}\n","import { OAuthProtectedResourceMetadata } from \"@modelcontextprotocol/sdk/shared/auth.js\";\nimport { getPublicUrl } from \"../lib/url\";\n\n/**\n * CORS headers for OAuth Protected Resource Metadata endpoint.\n * Configured to allow any origin to make the endpoint accessible to web-based MCP clients.\n */\nconst corsHeaders = {\n    \"Access-Control-Allow-Origin\": \"*\",\n    \"Access-Control-Allow-Methods\": \"GET, OPTIONS\",\n    \"Access-Control-Allow-Headers\": \"*\",\n    \"Access-Control-Max-Age\": \"86400\",\n};\n\n/**\n * OAuth 2.0 Protected Resource Metadata endpoint based on RFC 9728.\n * @see https://datatracker.ietf.org/doc/html/rfc9728\n *\n * @param authServerUrls - Array of issuer URLs of the OAuth 2.0 Authorization Servers.\n *                        These should match the \"issuer\" field in the authorization servers'\n *                        OAuth metadata (RFC 8414).\n * @param resourceUrl - Optional explicit resource URL override. When provided, this URL is\n *                      used instead of deriving it from the request. Use this when running\n *                      behind a proxy that doesn't set standard forwarding headers.\n *                      If not provided, the URL is automatically detected from proxy headers\n *                      (X-Forwarded-Host, X-Forwarded-Proto, Forwarded) or falls back to req.url.\n */\nexport function protectedResourceHandler({\n    authServerUrls,\n    resourceUrl: explicitResourceUrl,\n}: {\n    authServerUrls: string[];\n    resourceUrl?: string;\n}) {\n    return (req: Request) => {\n        let resource: string;\n\n        if (explicitResourceUrl) {\n            // Use explicit override if provided\n            resource = explicitResourceUrl;\n        } else {\n            // Auto-detect from proxy headers or req.url\n            const publicUrl = getPublicUrl(req);\n\n            publicUrl.pathname = publicUrl.pathname\n              .replace(/^\\/\\.well-known\\/[^\\/]+/, \"\");\n\n            // The URL class does not allow for empty `pathname` and will replace it\n            // with \"/\". Here, we correct that.\n            resource = publicUrl.pathname === '/'\n              ? publicUrl.toString().replace(/\\/$/, '')\n              : publicUrl.toString();\n        }\n\n        const metadata = generateProtectedResourceMetadata({\n            authServerUrls,\n            resourceUrl: resource,\n        });\n\n        return new Response(JSON.stringify(metadata), {\n            headers: {\n                ...corsHeaders,\n                \"Cache-Control\": \"max-age=3600\",\n                \"Content-Type\": \"application/json\",\n            },\n        });\n    };\n}\n\n/**\n * Generates protected resource metadata for the given auth server URLs and\n * protected resource identifier. The protected resource identifier, as defined\n * in RFC 9728, should be a a URL that uses the https scheme and has no fragment\n * component.\n *\n * @param authServerUrls - Array of issuer URLs of the authorization servers. Each URL should \n *                        match the \"issuer\" field in the respective authorization server's \n *                        OAuth metadata (RFC 8414).\n * @param resourceUrl - the protected resource identifier\n * @param additionalMetadata - Additional metadata fields to include in the response\n * @returns Protected resource metadata, serializable to JSON\n */\nexport function generateProtectedResourceMetadata({\n    authServerUrls,\n    resourceUrl,\n    additionalMetadata,\n}: {\n    authServerUrls: string[];\n    resourceUrl: string;\n    additionalMetadata?: Partial<OAuthProtectedResourceMetadata>;\n}): OAuthProtectedResourceMetadata {\n    return Object.assign(\n        {\n            resource: resourceUrl,\n            authorization_servers: authServerUrls\n        },\n        additionalMetadata\n    );\n}\n\n/**\n * CORS options request handler for OAuth metadata endpoints.\n * Necessary for MCP clients that operate in web browsers.\n */\nexport function metadataCorsOptionsRequestHandler() {\n    return () => {\n        return new Response(null, {\n            status: 200,\n            headers: corsHeaders,\n        });\n    };\n}\n\n"]}