agents 0.0.0-e48e5f9 → 0.0.0-e934f53

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/mcp/index.ts"],"sourcesContent":["import { DurableObject } from \"cloudflare:workers\";\nimport type { Server } from \"@modelcontextprotocol/sdk/server/index.js\";\nimport type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport type { Transport } from \"@modelcontextprotocol/sdk/shared/transport.js\";\nimport type { JSONRPCMessage } from \"@modelcontextprotocol/sdk/types.js\";\nimport {\n InitializeRequestSchema,\n JSONRPCMessageSchema,\n isJSONRPCError,\n isJSONRPCNotification,\n isJSONRPCRequest,\n isJSONRPCResponse\n} from \"@modelcontextprotocol/sdk/types.js\";\nimport type { Connection, WSMessage } from \"../\";\nimport { Agent } from \"../\";\n\nconst MAXIMUM_MESSAGE_SIZE_BYTES = 4 * 1024 * 1024; // 4MB\n\n// CORS helper functions\nfunction corsHeaders(_request: Request, corsOptions: CORSOptions = {}) {\n const origin = \"*\";\n return {\n \"Access-Control-Allow-Headers\":\n corsOptions.headers ||\n \"Content-Type, mcp-session-id, mcp-protocol-version\",\n \"Access-Control-Allow-Methods\": corsOptions.methods || \"GET, POST, OPTIONS\",\n \"Access-Control-Allow-Origin\": corsOptions.origin || origin,\n \"Access-Control-Expose-Headers\":\n corsOptions.exposeHeaders || \"mcp-session-id\",\n \"Access-Control-Max-Age\": (corsOptions.maxAge || 86400).toString()\n };\n}\n\nfunction isDurableObjectNamespace(\n namespace: unknown\n): namespace is DurableObjectNamespace<McpAgent> {\n return (\n typeof namespace === \"object\" &&\n namespace !== null &&\n \"newUniqueId\" in namespace &&\n typeof namespace.newUniqueId === \"function\" &&\n \"idFromName\" in namespace &&\n typeof namespace.idFromName === \"function\"\n );\n}\n\nfunction handleCORS(\n request: Request,\n corsOptions?: CORSOptions\n): Response | null {\n if (request.method === \"OPTIONS\") {\n return new Response(null, { headers: corsHeaders(request, corsOptions) });\n }\n\n return null;\n}\n\ninterface CORSOptions {\n origin?: string;\n methods?: string;\n headers?: string;\n maxAge?: number;\n exposeHeaders?: string;\n}\n\nclass McpSSETransport implements Transport {\n onclose?: () => void;\n onerror?: (error: Error) => void;\n onmessage?: (message: JSONRPCMessage) => void;\n sessionId?: string;\n\n private _getWebSocket: () => WebSocket | null;\n private _started = false;\n constructor(getWebSocket: () => WebSocket | null) {\n this._getWebSocket = getWebSocket;\n }\n\n async start() {\n // The transport does not manage the WebSocket connection since it's terminated\n // by the Durable Object in order to allow hibernation. There's nothing to initialize.\n if (this._started) {\n throw new Error(\"Transport already started\");\n }\n this._started = true;\n }\n\n async send(message: JSONRPCMessage) {\n if (!this._started) {\n throw new Error(\"Transport not started\");\n }\n const websocket = this._getWebSocket();\n if (!websocket) {\n throw new Error(\"WebSocket not connected\");\n }\n try {\n websocket.send(JSON.stringify(message));\n } catch (error) {\n this.onerror?.(error as Error);\n throw error;\n }\n }\n\n async close() {\n // Similar to start, the only thing to do is to pass the event on to the server\n this.onclose?.();\n }\n}\n\ntype TransportType = \"sse\" | \"streamable-http\" | \"unset\";\n\nclass McpStreamableHttpTransport implements Transport {\n onclose?: () => void;\n onerror?: (error: Error) => void;\n onmessage?: (message: JSONRPCMessage) => void;\n sessionId?: string;\n\n // TODO: If there is an open connection to send server-initiated messages\n // back, we should use that connection\n private _getWebSocketForGetRequest: () => WebSocket | null;\n\n // Get the appropriate websocket connection for a given message id\n private _getWebSocketForMessageID: (id: string) => WebSocket | null;\n\n // Notify the server that a response has been sent for a given message id\n // so that it may clean up it's mapping of message ids to connections\n // once they are no longer needed\n private _notifyResponseIdSent: (id: string) => void;\n\n private _started = false;\n constructor(\n getWebSocketForMessageID: (id: string) => WebSocket | null,\n notifyResponseIdSent: (id: string | number) => void\n ) {\n this._getWebSocketForMessageID = getWebSocketForMessageID;\n this._notifyResponseIdSent = notifyResponseIdSent;\n // TODO\n this._getWebSocketForGetRequest = () => null;\n }\n\n async start() {\n // The transport does not manage the WebSocket connection since it's terminated\n // by the Durable Object in order to allow hibernation. There's nothing to initialize.\n if (this._started) {\n throw new Error(\"Transport already started\");\n }\n this._started = true;\n }\n\n async send(message: JSONRPCMessage) {\n if (!this._started) {\n throw new Error(\"Transport not started\");\n }\n\n let websocket: WebSocket | null = null;\n\n if (isJSONRPCResponse(message) || isJSONRPCError(message)) {\n websocket = this._getWebSocketForMessageID(message.id.toString());\n if (!websocket) {\n throw new Error(\n `Could not find WebSocket for message id: ${message.id}`\n );\n }\n } else if (isJSONRPCRequest(message)) {\n // requests originating from the server must be sent over the\n // the connection created by a GET request\n websocket = this._getWebSocketForGetRequest();\n } else if (isJSONRPCNotification(message)) {\n // notifications do not have an id\n // but do have a relatedRequestId field\n // so that they can be sent to the correct connection\n websocket = null;\n }\n\n try {\n websocket?.send(JSON.stringify(message));\n if (isJSONRPCResponse(message)) {\n this._notifyResponseIdSent(message.id.toString());\n }\n } catch (error) {\n this.onerror?.(error as Error);\n throw error;\n }\n }\n\n async close() {\n // Similar to start, the only thing to do is to pass the event on to the server\n this.onclose?.();\n }\n}\n\ntype MaybePromise<T> = T | Promise<T>;\n\nexport abstract class McpAgent<\n Env = unknown,\n State = unknown,\n Props extends Record<string, unknown> = Record<string, unknown>\n> extends DurableObject<Env> {\n private _status: \"zero\" | \"starting\" | \"started\" = \"zero\";\n private _transport?: Transport;\n private _transportType: TransportType = \"unset\";\n private _requestIdToConnectionId: Map<string | number, string> = new Map();\n\n /**\n * Since McpAgent's _aren't_ yet real \"Agents\", let's only expose a couple of the methods\n * to the outer class: initialState/state/setState/onStateUpdate/sql\n */\n private _agent: Agent<Env, State>;\n\n get mcp() {\n return this._agent.mcp;\n }\n\n protected constructor(ctx: DurableObjectState, env: Env) {\n super(ctx, env);\n const self = this;\n\n this._agent = new (class extends Agent<Env, State> {\n static options = {\n hibernate: true\n };\n\n onStateUpdate(state: State | undefined, source: Connection | \"server\") {\n return self.onStateUpdate(state, source);\n }\n\n async onMessage(\n connection: Connection,\n message: WSMessage\n ): Promise<void> {\n return self.onMessage(connection, message);\n }\n })(ctx, env);\n }\n\n /**\n * Agents API allowlist\n */\n initialState!: State;\n get state() {\n return this._agent.state;\n }\n sql<T = Record<string, string | number | boolean | null>>(\n strings: TemplateStringsArray,\n ...values: (string | number | boolean | null)[]\n ) {\n return this._agent.sql<T>(strings, ...values);\n }\n\n setState(state: State) {\n return this._agent.setState(state);\n }\n // biome-ignore lint/correctness/noUnusedFunctionParameters: overriden later\n onStateUpdate(state: State | undefined, source: Connection | \"server\") {\n // override this to handle state updates\n }\n async onStart() {\n const self = this;\n\n this._agent = new (class extends Agent<Env, State> {\n initialState: State = self.initialState;\n static options = {\n hibernate: true\n };\n\n onStateUpdate(state: State | undefined, source: Connection | \"server\") {\n return self.onStateUpdate(state, source);\n }\n\n async onMessage(connection: Connection, event: WSMessage) {\n return self.onMessage(connection, event);\n }\n })(this.ctx, this.env);\n\n this.props = (await this.ctx.storage.get(\"props\")) as Props;\n this._transportType = (await this.ctx.storage.get(\n \"transportType\"\n )) as TransportType;\n await this._init(this.props);\n\n const server = await this.server;\n\n // Connect to the MCP server\n if (this._transportType === \"sse\") {\n this._transport = new McpSSETransport(() => this.getWebSocket());\n await server.connect(this._transport);\n } else if (this._transportType === \"streamable-http\") {\n this._transport = new McpStreamableHttpTransport(\n (id) => this.getWebSocketForResponseID(id),\n (id) => this._requestIdToConnectionId.delete(id)\n );\n await server.connect(this._transport);\n }\n }\n\n /**\n * McpAgent API\n */\n abstract server: MaybePromise<McpServer | Server>;\n props!: Props;\n initRun = false;\n\n abstract init(): Promise<void>;\n\n async _init(props: Props) {\n await this.ctx.storage.put(\"props\", props ?? {});\n if (!this.ctx.storage.get(\"transportType\")) {\n await this.ctx.storage.put(\"transportType\", \"unset\");\n }\n this.props = props;\n if (!this.initRun) {\n this.initRun = true;\n await this.init();\n }\n }\n\n async setInitialized() {\n await this.ctx.storage.put(\"initialized\", true);\n }\n\n async isInitialized() {\n return (await this.ctx.storage.get(\"initialized\")) === true;\n }\n\n private async _initialize(): Promise<void> {\n await this.ctx.blockConcurrencyWhile(async () => {\n this._status = \"starting\";\n await this.onStart();\n this._status = \"started\";\n });\n }\n\n // Allow the worker to fetch a websocket connection to the agent\n async fetch(request: Request): Promise<Response> {\n if (this._status !== \"started\") {\n // This means the server \"woke up\" after hibernation\n // so we need to hydrate it again\n await this._initialize();\n }\n\n // Only handle WebSocket upgrade requests\n if (request.headers.get(\"Upgrade\") !== \"websocket\") {\n return new Response(\"Expected WebSocket Upgrade request\", {\n status: 400\n });\n }\n\n // This request does not come from the user. The worker generates this\n // request to generate a websocket connection to the agent.\n const url = new URL(request.url);\n // This is not the path that the user requested, but the path that the worker\n // generated. We'll use this path to determine which transport to use.\n const path = url.pathname;\n const server = await this.server;\n\n switch (path) {\n case \"/sse\": {\n // For SSE connections, we can only have one open connection per session\n // If we get an upgrade while already connected, we should error\n const websockets = this.ctx.getWebSockets();\n if (websockets.length > 0) {\n return new Response(\"Websocket already connected\", { status: 400 });\n }\n\n // This session must always use the SSE transporo\n await this.ctx.storage.put(\"transportType\", \"sse\");\n this._transportType = \"sse\";\n\n if (!this._transport) {\n this._transport = new McpSSETransport(() => this.getWebSocket());\n await server.connect(this._transport);\n }\n\n // Defer to the Agent's fetch method to handle the WebSocket connection\n return this._agent.fetch(request);\n }\n case \"/streamable-http\": {\n if (!this._transport) {\n this._transport = new McpStreamableHttpTransport(\n (id) => this.getWebSocketForResponseID(id),\n (id) => this._requestIdToConnectionId.delete(id)\n );\n await server.connect(this._transport);\n }\n\n // This session must always use the streamable-http transport\n await this.ctx.storage.put(\"transportType\", \"streamable-http\");\n this._transportType = \"streamable-http\";\n\n return this._agent.fetch(request);\n }\n default:\n return new Response(\n \"Internal Server Error: Expected /sse or /streamable-http path\",\n {\n status: 500\n }\n );\n }\n }\n\n getWebSocket() {\n const websockets = this.ctx.getWebSockets();\n if (websockets.length === 0) {\n return null;\n }\n return websockets[0];\n }\n\n getWebSocketForResponseID(id: string): WebSocket | null {\n const connectionId = this._requestIdToConnectionId.get(id);\n if (connectionId === undefined) {\n return null;\n }\n return this._agent.getConnection(connectionId) ?? null;\n }\n\n // All messages received here. This is currently never called\n async onMessage(connection: Connection, event: WSMessage) {\n // Since we address the DO via both the protocol and the session id,\n // this should never happen, but let's enforce it just in case\n if (this._transportType !== \"streamable-http\") {\n const err = new Error(\n \"Internal Server Error: Expected streamable-http protocol\"\n );\n this._transport?.onerror?.(err);\n return;\n }\n\n let message: JSONRPCMessage;\n try {\n // Ensure event is a string\n const data =\n typeof event === \"string\" ? event : new TextDecoder().decode(event);\n message = JSONRPCMessageSchema.parse(JSON.parse(data));\n } catch (error) {\n this._transport?.onerror?.(error as Error);\n return;\n }\n\n // We need to map every incoming message to the connection that it came in on\n // so that we can send relevant responses and notifications back on the same connection\n if (isJSONRPCRequest(message)) {\n this._requestIdToConnectionId.set(message.id.toString(), connection.id);\n }\n\n this._transport?.onmessage?.(message);\n }\n\n // All messages received over SSE after the initial connection has been established\n // will be passed here\n async onSSEMcpMessage(\n _sessionId: string,\n request: Request\n ): Promise<Error | null> {\n if (this._status !== \"started\") {\n // This means the server \"woke up\" after hibernation\n // so we need to hydrate it again\n await this._initialize();\n }\n\n // Since we address the DO via both the protocol and the session id,\n // this should never happen, but let's enforce it just in case\n if (this._transportType !== \"sse\") {\n return new Error(\"Internal Server Error: Expected SSE protocol\");\n }\n\n try {\n const message = await request.json();\n let parsedMessage: JSONRPCMessage;\n try {\n parsedMessage = JSONRPCMessageSchema.parse(message);\n } catch (error) {\n this._transport?.onerror?.(error as Error);\n throw error;\n }\n\n this._transport?.onmessage?.(parsedMessage);\n return null;\n } catch (error) {\n console.error(\"Error forwarding message to SSE:\", error);\n this._transport?.onerror?.(error as Error);\n return error as Error;\n }\n }\n\n // Delegate all websocket events to the underlying agent\n async webSocketMessage(\n ws: WebSocket,\n event: ArrayBuffer | string\n ): Promise<void> {\n if (this._status !== \"started\") {\n // This means the server \"woke up\" after hibernation\n // so we need to hydrate it again\n await this._initialize();\n }\n return await this._agent.webSocketMessage(ws, event);\n }\n\n // WebSocket event handlers for hibernation support\n async webSocketError(ws: WebSocket, error: unknown): Promise<void> {\n if (this._status !== \"started\") {\n // This means the server \"woke up\" after hibernation\n // so we need to hydrate it again\n await this._initialize();\n }\n return await this._agent.webSocketError(ws, error);\n }\n\n async webSocketClose(\n ws: WebSocket,\n code: number,\n reason: string,\n wasClean: boolean\n ): Promise<void> {\n if (this._status !== \"started\") {\n // This means the server \"woke up\" after hibernation\n // so we need to hydrate it again\n await this._initialize();\n }\n return await this._agent.webSocketClose(ws, code, reason, wasClean);\n }\n\n static mount(\n path: string,\n {\n binding = \"MCP_OBJECT\",\n corsOptions\n }: {\n binding?: string;\n corsOptions?: CORSOptions;\n } = {}\n ) {\n return McpAgent.serveSSE(path, { binding, corsOptions });\n }\n\n static serveSSE(\n path: string,\n {\n binding = \"MCP_OBJECT\",\n corsOptions\n }: {\n binding?: string;\n corsOptions?: CORSOptions;\n } = {}\n ) {\n let pathname = path;\n if (path === \"/\") {\n pathname = \"/*\";\n }\n const basePattern = new URLPattern({ pathname });\n const messagePattern = new URLPattern({ pathname: `${pathname}/message` });\n\n return {\n async fetch<Env>(\n this: void,\n request: Request,\n env: Env,\n ctx: ExecutionContext\n ): Promise<Response> {\n // Handle CORS preflight\n const corsResponse = handleCORS(request, corsOptions);\n if (corsResponse) return corsResponse;\n\n const url = new URL(request.url);\n const bindingValue = env[binding as keyof typeof env] as unknown;\n\n // Ensure we have a binding of some sort\n if (bindingValue == null || typeof bindingValue !== \"object\") {\n console.error(\n `Could not find McpAgent binding for ${binding}. Did you update your wrangler configuration?`\n );\n return new Response(\"Invalid binding\", { status: 500 });\n }\n\n // Ensure that the binding is to a DurableObject\n if (!isDurableObjectNamespace(bindingValue)) {\n return new Response(\"Invalid binding\", { status: 500 });\n }\n\n const namespace =\n bindingValue satisfies DurableObjectNamespace<McpAgent>;\n\n // Handle initial SSE connection\n if (request.method === \"GET\" && basePattern.test(url)) {\n // Use a session ID if one is passed in, or create a unique\n // session ID for this connection\n const sessionId =\n url.searchParams.get(\"sessionId\") ||\n namespace.newUniqueId().toString();\n\n // Create a Transform Stream for SSE\n const { readable, writable } = new TransformStream();\n const writer = writable.getWriter();\n const encoder = new TextEncoder();\n\n // Send the endpoint event\n const endpointUrl = new URL(request.url);\n endpointUrl.pathname = encodeURI(`${pathname}/message`);\n endpointUrl.searchParams.set(\"sessionId\", sessionId);\n const relativeUrlWithSession =\n endpointUrl.pathname + endpointUrl.search + endpointUrl.hash;\n const endpointMessage = `event: endpoint\\ndata: ${relativeUrlWithSession}\\n\\n`;\n writer.write(encoder.encode(endpointMessage));\n\n // Get the Durable Object\n const id = namespace.idFromName(`sse:${sessionId}`);\n const doStub = namespace.get(id);\n\n // Initialize the object\n await doStub._init(ctx.props);\n\n // Connect to the Durable Object via WebSocket\n const upgradeUrl = new URL(request.url);\n // enforce that the path that the DO receives is always /sse\n upgradeUrl.pathname = \"/sse\";\n const response = await doStub.fetch(\n new Request(upgradeUrl, {\n headers: {\n Upgrade: \"websocket\",\n // Required by PartyServer\n \"x-partykit-room\": sessionId\n }\n })\n );\n\n // Get the WebSocket\n const ws = response.webSocket;\n if (!ws) {\n console.error(\"Failed to establish WebSocket connection\");\n await writer.close();\n return new Response(\"Failed to establish WebSocket connection\", {\n status: 500\n });\n }\n\n // Accept the WebSocket\n ws.accept();\n\n // Handle messages from the Durable Object\n ws.addEventListener(\"message\", (event) => {\n async function onMessage(event: MessageEvent) {\n try {\n const message = JSON.parse(event.data);\n\n // validate that the message is a valid JSONRPC message\n const result = JSONRPCMessageSchema.safeParse(message);\n if (!result.success) {\n // The message was not a valid JSONRPC message, so we will drop it\n // PartyKit will broadcast state change messages to all connected clients\n // and we need to filter those out so they are not passed to MCP clients\n return;\n }\n\n // Send the message as an SSE event\n const messageText = `event: message\\ndata: ${JSON.stringify(result.data)}\\n\\n`;\n await writer.write(encoder.encode(messageText));\n } catch (error) {\n console.error(\"Error forwarding message to SSE:\", error);\n }\n }\n onMessage(event).catch(console.error);\n });\n\n // Handle WebSocket errors\n ws.addEventListener(\"error\", (error) => {\n async function onError(_error: Event) {\n try {\n await writer.close();\n } catch (_e) {\n // Ignore errors when closing\n }\n }\n onError(error).catch(console.error);\n });\n\n // Handle WebSocket closure\n ws.addEventListener(\"close\", () => {\n async function onClose() {\n try {\n await writer.close();\n } catch (error) {\n console.error(\"Error closing SSE connection:\", error);\n }\n }\n onClose().catch(console.error);\n });\n\n // Return the SSE response\n return new Response(readable, {\n headers: {\n \"Cache-Control\": \"no-cache\",\n Connection: \"keep-alive\",\n \"Content-Type\": \"text/event-stream\",\n ...corsHeaders(request, corsOptions)\n }\n });\n }\n\n // Handle incoming MCP messages. These will be passed to McpAgent\n // but the response will be sent back via the open SSE connection\n // so we only need to return a 202 Accepted response for success\n if (request.method === \"POST\" && messagePattern.test(url)) {\n const sessionId = url.searchParams.get(\"sessionId\");\n if (!sessionId) {\n return new Response(\n `Missing sessionId. Expected POST to ${pathname} to initiate new one`,\n { status: 400 }\n );\n }\n\n const contentType = request.headers.get(\"content-type\") || \"\";\n if (!contentType.includes(\"application/json\")) {\n return new Response(`Unsupported content-type: ${contentType}`, {\n status: 400\n });\n }\n\n // check if the request body is too large\n const contentLength = Number.parseInt(\n request.headers.get(\"content-length\") || \"0\",\n 10\n );\n if (contentLength > MAXIMUM_MESSAGE_SIZE_BYTES) {\n return new Response(\n `Request body too large: ${contentLength} bytes`,\n {\n status: 400\n }\n );\n }\n\n // Get the Durable Object\n const id = namespace.idFromName(`sse:${sessionId}`);\n const doStub = namespace.get(id);\n\n // Forward the request to the Durable Object\n const error = await doStub.onSSEMcpMessage(sessionId, request);\n\n if (error) {\n return new Response(error.message, {\n headers: {\n \"Cache-Control\": \"no-cache\",\n Connection: \"keep-alive\",\n \"Content-Type\": \"text/event-stream\",\n ...corsHeaders(request, corsOptions)\n },\n status: 400\n });\n }\n\n return new Response(\"Accepted\", {\n headers: {\n \"Cache-Control\": \"no-cache\",\n Connection: \"keep-alive\",\n \"Content-Type\": \"text/event-stream\",\n ...corsHeaders(request, corsOptions)\n },\n status: 202\n });\n }\n\n return new Response(\"Not Found\", { status: 404 });\n }\n };\n }\n\n static serve(\n path: string,\n {\n binding = \"MCP_OBJECT\",\n corsOptions\n }: { binding?: string; corsOptions?: CORSOptions } = {}\n ) {\n let pathname = path;\n if (path === \"/\") {\n pathname = \"/*\";\n }\n const basePattern = new URLPattern({ pathname });\n\n return {\n async fetch<Env>(\n this: void,\n request: Request,\n env: Env,\n ctx: ExecutionContext\n ): Promise<Response> {\n // Handle CORS preflight\n const corsResponse = handleCORS(request, corsOptions);\n if (corsResponse) {\n return corsResponse;\n }\n\n const url = new URL(request.url);\n const bindingValue = env[binding as keyof typeof env] as unknown;\n\n // Ensure we have a binding of some sort\n if (bindingValue == null || typeof bindingValue !== \"object\") {\n console.error(\n `Could not find McpAgent binding for ${binding}. Did you update your wrangler configuration?`\n );\n return new Response(\"Invalid binding\", { status: 500 });\n }\n\n // Ensure that the binding is to a DurableObject\n if (!isDurableObjectNamespace(bindingValue)) {\n return new Response(\"Invalid binding\", { status: 500 });\n }\n\n const namespace =\n bindingValue satisfies DurableObjectNamespace<McpAgent>;\n\n if (request.method === \"POST\" && basePattern.test(url)) {\n // validate the Accept header\n const acceptHeader = request.headers.get(\"accept\");\n // The client MUST include an Accept header, listing both application/json and text/event-stream as supported content types.\n if (\n !acceptHeader?.includes(\"application/json\") ||\n !acceptHeader.includes(\"text/event-stream\")\n ) {\n const body = JSON.stringify({\n error: {\n code: -32000,\n message:\n \"Not Acceptable: Client must accept both application/json and text/event-stream\"\n },\n id: null,\n jsonrpc: \"2.0\"\n });\n return new Response(body, { status: 406 });\n }\n\n const ct = request.headers.get(\"content-type\");\n if (!ct || !ct.includes(\"application/json\")) {\n const body = JSON.stringify({\n error: {\n code: -32000,\n message:\n \"Unsupported Media Type: Content-Type must be application/json\"\n },\n id: null,\n jsonrpc: \"2.0\"\n });\n return new Response(body, { status: 415 });\n }\n\n // Check content length against maximum allowed size\n const contentLength = Number.parseInt(\n request.headers.get(\"content-length\") ?? \"0\",\n 10\n );\n if (contentLength > MAXIMUM_MESSAGE_SIZE_BYTES) {\n const body = JSON.stringify({\n error: {\n code: -32000,\n message: `Request body too large. Maximum size is ${MAXIMUM_MESSAGE_SIZE_BYTES} bytes`\n },\n id: null,\n jsonrpc: \"2.0\"\n });\n return new Response(body, { status: 413 });\n }\n\n let sessionId = request.headers.get(\"mcp-session-id\");\n let rawMessage: unknown;\n\n try {\n rawMessage = await request.json();\n } catch (_error) {\n const body = JSON.stringify({\n error: {\n code: -32700,\n message: \"Parse error: Invalid JSON\"\n },\n id: null,\n jsonrpc: \"2.0\"\n });\n return new Response(body, { status: 400 });\n }\n\n // Make sure the message is an array to simplify logic\n let arrayMessage: unknown[];\n if (Array.isArray(rawMessage)) {\n arrayMessage = rawMessage;\n } else {\n arrayMessage = [rawMessage];\n }\n\n let messages: JSONRPCMessage[] = [];\n\n // Try to parse each message as JSON RPC. Fail if any message is invalid\n for (const msg of arrayMessage) {\n if (!JSONRPCMessageSchema.safeParse(msg).success) {\n const body = JSON.stringify({\n error: {\n code: -32700,\n message: \"Parse error: Invalid JSON-RPC message\"\n },\n id: null,\n jsonrpc: \"2.0\"\n });\n return new Response(body, { status: 400 });\n }\n }\n\n messages = arrayMessage.map((msg) => JSONRPCMessageSchema.parse(msg));\n\n // Before we pass the messages to the agent, there's another error condition we need to enforce\n // Check if this is an initialization request\n // https://spec.modelcontextprotocol.io/specification/2025-03-26/basic/lifecycle/\n const isInitializationRequest = messages.some(\n (msg) => InitializeRequestSchema.safeParse(msg).success\n );\n\n if (isInitializationRequest && sessionId) {\n const body = JSON.stringify({\n error: {\n code: -32600,\n message:\n \"Invalid Request: Initialization requests must not include a sessionId\"\n },\n id: null,\n jsonrpc: \"2.0\"\n });\n return new Response(body, { status: 400 });\n }\n\n // The initialization request must be the only request in the batch\n if (isInitializationRequest && messages.length > 1) {\n const body = JSON.stringify({\n error: {\n code: -32600,\n message:\n \"Invalid Request: Only one initialization request is allowed\"\n },\n id: null,\n jsonrpc: \"2.0\"\n });\n return new Response(body, { status: 400 });\n }\n\n // If an Mcp-Session-Id is returned by the server during initialization,\n // clients using the Streamable HTTP transport MUST include it\n // in the Mcp-Session-Id header on all of their subsequent HTTP requests.\n if (!isInitializationRequest && !sessionId) {\n const body = JSON.stringify({\n error: {\n code: -32000,\n message: \"Bad Request: Mcp-Session-Id header is required\"\n },\n id: null,\n jsonrpc: \"2.0\"\n });\n return new Response(body, { status: 400 });\n }\n\n // If we don't have a sessionId, we are serving an initialization request\n // and need to generate a new sessionId\n sessionId = sessionId ?? namespace.newUniqueId().toString();\n\n // fetch the agent DO\n const id = namespace.idFromName(`streamable-http:${sessionId}`);\n const doStub = namespace.get(id);\n const isInitialized = await doStub.isInitialized();\n\n if (isInitializationRequest) {\n await doStub._init(ctx.props);\n await doStub.setInitialized();\n } else if (!isInitialized) {\n // if we have gotten here, then a session id that was never initialized\n // was provided\n const body = JSON.stringify({\n error: {\n code: -32001,\n message: \"Session not found\"\n },\n id: null,\n jsonrpc: \"2.0\"\n });\n return new Response(body, { status: 404 });\n }\n\n // We've evaluated all the error conditions! Now it's time to establish\n // all the streams\n\n // Create a Transform Stream for SSE\n const { readable, writable } = new TransformStream();\n const writer = writable.getWriter();\n const encoder = new TextEncoder();\n\n // Connect to the Durable Object via WebSocket\n const upgradeUrl = new URL(request.url);\n upgradeUrl.pathname = \"/streamable-http\";\n const response = await doStub.fetch(\n new Request(upgradeUrl, {\n headers: {\n Upgrade: \"websocket\",\n // Required by PartyServer\n \"x-partykit-room\": sessionId\n }\n })\n );\n\n // Get the WebSocket\n const ws = response.webSocket;\n if (!ws) {\n console.error(\"Failed to establish WebSocket connection\");\n\n await writer.close();\n const body = JSON.stringify({\n error: {\n code: -32001,\n message: \"Failed to establish WebSocket connection\"\n },\n id: null,\n jsonrpc: \"2.0\"\n });\n return new Response(body, { status: 500 });\n }\n\n // Keep track of the request ids that we have sent to the server\n // so that we can close the connection once we have received\n // all the responses\n const requestIds: Set<string | number> = new Set();\n\n // Accept the WebSocket\n ws.accept();\n\n // Handle messages from the Durable Object\n ws.addEventListener(\"message\", (event) => {\n async function onMessage(event: MessageEvent) {\n try {\n const data =\n typeof event.data === \"string\"\n ? event.data\n : new TextDecoder().decode(event.data);\n const message = JSON.parse(data);\n\n // validate that the message is a valid JSONRPC message\n const result = JSONRPCMessageSchema.safeParse(message);\n if (!result.success) {\n // The message was not a valid JSONRPC message, so we will drop it\n // PartyKit will broadcast state change messages to all connected clients\n // and we need to filter those out so they are not passed to MCP clients\n return;\n }\n\n // If the message is a response or an error, remove the id from the set of\n // request ids\n if (\n isJSONRPCResponse(result.data) ||\n isJSONRPCError(result.data)\n ) {\n requestIds.delete(result.data.id);\n }\n\n // Send the message as an SSE event\n const messageText = `event: message\\ndata: ${JSON.stringify(result.data)}\\n\\n`;\n await writer.write(encoder.encode(messageText));\n\n // If we have received all the responses, close the connection\n if (requestIds.size === 0) {\n ws!.close();\n }\n } catch (error) {\n console.error(\"Error forwarding message to SSE:\", error);\n }\n }\n onMessage(event).catch(console.error);\n });\n\n // Handle WebSocket errors\n ws.addEventListener(\"error\", (error) => {\n async function onError(_error: Event) {\n try {\n await writer.close();\n } catch (_e) {\n // Ignore errors when closing\n }\n }\n onError(error).catch(console.error);\n });\n\n // Handle WebSocket closure\n ws.addEventListener(\"close\", () => {\n async function onClose() {\n try {\n await writer.close();\n } catch (error) {\n console.error(\"Error closing SSE connection:\", error);\n }\n }\n onClose().catch(console.error);\n });\n\n // If there are no requests, we send the messages to the agent and acknowledge the request with a 202\n // since we don't expect any responses back through this connection\n const hasOnlyNotificationsOrResponses = messages.every(\n (msg) => isJSONRPCNotification(msg) || isJSONRPCResponse(msg)\n );\n if (hasOnlyNotificationsOrResponses) {\n for (const message of messages) {\n ws.send(JSON.stringify(message));\n }\n\n // closing the websocket will also close the SSE connection\n ws.close();\n\n return new Response(null, {\n headers: corsHeaders(request, corsOptions),\n status: 202\n });\n }\n\n for (const message of messages) {\n if (isJSONRPCRequest(message)) {\n // add each request id that we send off to a set\n // so that we can keep track of which requests we\n // still need a response for\n requestIds.add(message.id);\n }\n ws.send(JSON.stringify(message));\n }\n\n // Return the SSE response. We handle closing the stream in the ws \"message\"\n // handler\n return new Response(readable, {\n headers: {\n \"Cache-Control\": \"no-cache\",\n Connection: \"keep-alive\",\n \"Content-Type\": \"text/event-stream\",\n \"mcp-session-id\": sessionId,\n ...corsHeaders(request, corsOptions)\n },\n status: 200\n });\n }\n\n // We don't yet support GET or DELETE requests\n const body = JSON.stringify({\n error: {\n code: -32000,\n message: \"Method not allowed\"\n },\n id: null,\n jsonrpc: \"2.0\"\n });\n return new Response(body, { status: 405 });\n }\n };\n }\n}\n"],"mappings":"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","names":["event","body"]}
1
+ {"version":3,"sources":["../../src/mcp/index.ts"],"sourcesContent":["import { DurableObject } from \"cloudflare:workers\";\nimport type { Server } from \"@modelcontextprotocol/sdk/server/index.js\";\nimport type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport type { Transport } from \"@modelcontextprotocol/sdk/shared/transport.js\";\nimport type { JSONRPCMessage } from \"@modelcontextprotocol/sdk/types.js\";\nimport {\n InitializeRequestSchema,\n JSONRPCMessageSchema,\n isJSONRPCError,\n isJSONRPCNotification,\n isJSONRPCRequest,\n isJSONRPCResponse,\n type ElicitResult\n} from \"@modelcontextprotocol/sdk/types.js\";\nimport type { Connection, WSMessage } from \"../\";\nimport { Agent } from \"../index\";\n\nconst MAXIMUM_MESSAGE_SIZE_BYTES = 4 * 1024 * 1024; // 4MB\n\n// CORS helper functions\nfunction corsHeaders(_request: Request, corsOptions: CORSOptions = {}) {\n const origin = \"*\";\n return {\n \"Access-Control-Allow-Headers\":\n corsOptions.headers ||\n \"Content-Type, mcp-session-id, mcp-protocol-version\",\n \"Access-Control-Allow-Methods\": corsOptions.methods || \"GET, POST, OPTIONS\",\n \"Access-Control-Allow-Origin\": corsOptions.origin || origin,\n \"Access-Control-Expose-Headers\":\n corsOptions.exposeHeaders || \"mcp-session-id\",\n \"Access-Control-Max-Age\": (corsOptions.maxAge || 86400).toString()\n };\n}\n\nfunction isDurableObjectNamespace(\n namespace: unknown\n): namespace is DurableObjectNamespace<McpAgent> {\n return (\n typeof namespace === \"object\" &&\n namespace !== null &&\n \"newUniqueId\" in namespace &&\n typeof namespace.newUniqueId === \"function\" &&\n \"idFromName\" in namespace &&\n typeof namespace.idFromName === \"function\"\n );\n}\n\nfunction handleCORS(\n request: Request,\n corsOptions?: CORSOptions\n): Response | null {\n if (request.method === \"OPTIONS\") {\n return new Response(null, { headers: corsHeaders(request, corsOptions) });\n }\n\n return null;\n}\n\ninterface CORSOptions {\n origin?: string;\n methods?: string;\n headers?: string;\n maxAge?: number;\n exposeHeaders?: string;\n}\n\nclass McpSSETransport implements Transport {\n onclose?: () => void;\n onerror?: (error: Error) => void;\n onmessage?: (message: JSONRPCMessage) => void;\n sessionId?: string;\n\n private _getWebSocket: () => WebSocket | null;\n private _started = false;\n constructor(getWebSocket: () => WebSocket | null) {\n this._getWebSocket = getWebSocket;\n }\n\n async start() {\n // The transport does not manage the WebSocket connection since it's terminated\n // by the Durable Object in order to allow hibernation. There's nothing to initialize.\n if (this._started) {\n throw new Error(\"Transport already started\");\n }\n this._started = true;\n }\n\n async send(message: JSONRPCMessage) {\n if (!this._started) {\n throw new Error(\"Transport not started\");\n }\n const websocket = this._getWebSocket();\n if (!websocket) {\n throw new Error(\"WebSocket not connected\");\n }\n try {\n websocket.send(JSON.stringify(message));\n } catch (error) {\n this.onerror?.(error as Error);\n throw error;\n }\n }\n\n async close() {\n // Similar to start, the only thing to do is to pass the event on to the server\n this.onclose?.();\n }\n}\n\ntype TransportType = \"sse\" | \"streamable-http\" | \"unset\";\n\nclass McpStreamableHttpTransport implements Transport {\n onclose?: () => void;\n onerror?: (error: Error) => void;\n onmessage?: (message: JSONRPCMessage) => void;\n sessionId?: string;\n\n // TODO: If there is an open connection to send server-initiated messages\n // back, we should use that connection\n private _getWebSocketForGetRequest: () => WebSocket | null;\n\n // Get the appropriate websocket connection for a given message id\n private _getWebSocketForMessageID: (id: string) => WebSocket | null;\n\n // Notify the server that a response has been sent for a given message id\n // so that it may clean up it's mapping of message ids to connections\n // once they are no longer needed\n private _notifyResponseIdSent: (id: string) => void;\n\n private _started = false;\n constructor(\n getWebSocketForMessageID: (id: string) => WebSocket | null,\n notifyResponseIdSent: (id: string | number) => void\n ) {\n this._getWebSocketForMessageID = getWebSocketForMessageID;\n this._notifyResponseIdSent = notifyResponseIdSent;\n // TODO\n this._getWebSocketForGetRequest = () => null;\n }\n\n async start() {\n // The transport does not manage the WebSocket connection since it's terminated\n // by the Durable Object in order to allow hibernation. There's nothing to initialize.\n if (this._started) {\n throw new Error(\"Transport already started\");\n }\n this._started = true;\n }\n\n async send(message: JSONRPCMessage) {\n if (!this._started) {\n throw new Error(\"Transport not started\");\n }\n\n let websocket: WebSocket | null = null;\n\n if (isJSONRPCResponse(message) || isJSONRPCError(message)) {\n websocket = this._getWebSocketForMessageID(message.id.toString());\n if (!websocket) {\n throw new Error(\n `Could not find WebSocket for message id: ${message.id}`\n );\n }\n } else if (isJSONRPCRequest(message)) {\n // requests originating from the server must be sent over the\n // the connection created by a GET request\n websocket = this._getWebSocketForGetRequest();\n } else if (isJSONRPCNotification(message)) {\n // notifications do not have an id\n // but do have a relatedRequestId field\n // so that they can be sent to the correct connection\n websocket = null;\n }\n\n try {\n websocket?.send(JSON.stringify(message));\n if (isJSONRPCResponse(message)) {\n this._notifyResponseIdSent(message.id.toString());\n }\n } catch (error) {\n this.onerror?.(error as Error);\n throw error;\n }\n }\n\n async close() {\n // Similar to start, the only thing to do is to pass the event on to the server\n this.onclose?.();\n }\n}\n\ntype MaybePromise<T> = T | Promise<T>;\n\nexport abstract class McpAgent<\n Env = unknown,\n State = unknown,\n Props extends Record<string, unknown> = Record<string, unknown>\n> extends DurableObject<Env> {\n private _status: \"zero\" | \"starting\" | \"started\" = \"zero\";\n private _transport?: Transport;\n private _transportType: TransportType = \"unset\";\n private _requestIdToConnectionId: Map<string | number, string> = new Map();\n\n // Hibernation-safe elicitation handling\n // Uses durable storage instead of in-memory handlers\n\n /**\n * Since McpAgent's _aren't_ yet real \"Agents\", let's only expose a couple of the methods\n * to the outer class: initialState/state/setState/onStateUpdate/sql\n */\n private _agent: Agent<Env, State>;\n\n get mcp() {\n return this._agent.mcp;\n }\n\n protected constructor(ctx: DurableObjectState, env: Env) {\n super(ctx, env);\n const self = this;\n\n this._agent = new (class extends Agent<Env, State> {\n static options = {\n hibernate: true\n };\n\n onStateUpdate(state: State | undefined, source: Connection | \"server\") {\n return self.onStateUpdate(state, source);\n }\n\n async onMessage(\n connection: Connection,\n message: WSMessage\n ): Promise<void> {\n return self.onMessage(connection, message);\n }\n })(ctx, env);\n }\n\n /**\n * Agents API allowlist\n */\n initialState!: State;\n get state() {\n return this._agent.state;\n }\n sql<T = Record<string, string | number | boolean | null>>(\n strings: TemplateStringsArray,\n ...values: (string | number | boolean | null)[]\n ) {\n return this._agent.sql<T>(strings, ...values);\n }\n\n setState(state: State) {\n return this._agent.setState(state);\n }\n\n /**\n * Elicit user input with a message and schema\n */\n async elicitInput(params: {\n message: string;\n requestedSchema: unknown;\n }): Promise<ElicitResult> {\n const requestId = `elicit_${Math.random().toString(36).substring(2, 11)}`;\n\n // Store pending request in durable storage\n await this.ctx.storage.put(`elicitation:${requestId}`, {\n message: params.message,\n requestedSchema: params.requestedSchema,\n timestamp: Date.now()\n });\n\n const elicitRequest = {\n jsonrpc: \"2.0\" as const,\n id: requestId,\n method: \"elicitation/create\",\n params: {\n message: params.message,\n requestedSchema: params.requestedSchema\n }\n };\n\n // Send through MCP transport\n if (this._transport) {\n await this._transport.send(elicitRequest);\n } else {\n const connections = this._agent?.getConnections();\n if (!connections || Array.from(connections).length === 0) {\n await this.ctx.storage.delete(`elicitation:${requestId}`);\n throw new Error(\"No active connections available for elicitation\");\n }\n\n const connectionList = Array.from(connections);\n for (const connection of connectionList) {\n try {\n connection.send(JSON.stringify(elicitRequest));\n } catch (error) {\n console.error(\"Failed to send elicitation request:\", error);\n }\n }\n }\n\n // Wait for response through MCP\n return this._waitForElicitationResponse(requestId);\n }\n\n // we leave the variables as unused for autocomplete purposes\n // biome-ignore lint/correctness/noUnusedFunctionParameters: overriden later\n onStateUpdate(state: State | undefined, source: Connection | \"server\") {\n // override this to handle state updates\n }\n async onStart() {\n const self = this;\n\n this._agent = new (class extends Agent<Env, State> {\n initialState: State = self.initialState;\n static options = {\n hibernate: true\n };\n\n onStateUpdate(state: State | undefined, source: Connection | \"server\") {\n return self.onStateUpdate(state, source);\n }\n\n async onMessage(connection: Connection, event: WSMessage) {\n return self.onMessage(connection, event);\n }\n })(this.ctx, this.env);\n\n this.props = (await this.ctx.storage.get(\"props\")) as Props;\n this._transportType = (await this.ctx.storage.get(\n \"transportType\"\n )) as TransportType;\n await this._init(this.props);\n\n const server = await this.server;\n\n // Connect to the MCP server\n if (this._transportType === \"sse\") {\n this._transport = new McpSSETransport(() => this.getWebSocket());\n await server.connect(this._transport);\n } else if (this._transportType === \"streamable-http\") {\n this._transport = new McpStreamableHttpTransport(\n (id) => this.getWebSocketForResponseID(id),\n (id) => this._requestIdToConnectionId.delete(id)\n );\n await server.connect(this._transport);\n }\n }\n\n /**\n * McpAgent API\n */\n abstract server: MaybePromise<McpServer | Server>;\n props!: Props;\n initRun = false;\n\n abstract init(): Promise<void>;\n\n /**\n * Handle errors that occur during initialization or operation.\n * Override this method to provide custom error handling.\n * @param error - The error that occurred\n * @returns An error response object with status code and message\n */\n onError(error: Error): { status: number; message: string } {\n console.error(\"McpAgent error:\", error);\n return {\n status: 500,\n message:\n error.message || \"An unexpected error occurred during initialization\"\n };\n }\n\n async _init(props: Props) {\n await this.updateProps(props);\n if (!this.ctx.storage.get(\"transportType\")) {\n await this.ctx.storage.put(\"transportType\", \"unset\");\n }\n if (!this.initRun) {\n this.initRun = true;\n try {\n await this.init();\n } catch (error) {\n const errorResponse = this.onError(error as Error);\n throw new Error(`Initialization failed: ${errorResponse.message}`);\n }\n }\n }\n\n async setInitialized() {\n await this.ctx.storage.put(\"initialized\", true);\n }\n\n async isInitialized() {\n return (await this.ctx.storage.get(\"initialized\")) === true;\n }\n\n async updateProps(props: Props) {\n await this.ctx.storage.put(\"props\", props ?? {});\n this.props = props;\n }\n\n private async _initialize(): Promise<void> {\n await this.ctx.blockConcurrencyWhile(async () => {\n this._status = \"starting\";\n await this.onStart();\n this._status = \"started\";\n });\n }\n\n // Allow the worker to fetch a websocket connection to the agent\n async fetch(request: Request): Promise<Response> {\n if (this._status !== \"started\") {\n // This means the server \"woke up\" after hibernation\n // so we need to hydrate it again\n await this._initialize();\n }\n\n // Only handle WebSocket upgrade requests\n if (request.headers.get(\"Upgrade\") !== \"websocket\") {\n return new Response(\"Expected WebSocket Upgrade request\", {\n status: 400\n });\n }\n\n // This request does not come from the user. The worker generates this\n // request to generate a websocket connection to the agent.\n const url = new URL(request.url);\n // This is not the path that the user requested, but the path that the worker\n // generated. We'll use this path to determine which transport to use.\n const path = url.pathname;\n const server = await this.server;\n\n switch (path) {\n case \"/sse\": {\n // For SSE connections, we can only have one open connection per session\n // If we get an upgrade while already connected, we should error\n const websockets = this.ctx.getWebSockets();\n if (websockets.length > 0) {\n return new Response(\"Websocket already connected\", { status: 400 });\n }\n\n // This session must always use the SSE transporo\n await this.ctx.storage.put(\"transportType\", \"sse\");\n this._transportType = \"sse\";\n\n if (!this._transport) {\n this._transport = new McpSSETransport(() => this.getWebSocket());\n await server.connect(this._transport);\n }\n\n // Defer to the Agent's fetch method to handle the WebSocket connection\n return this._agent.fetch(request);\n }\n case \"/streamable-http\": {\n if (!this._transport) {\n this._transport = new McpStreamableHttpTransport(\n (id) => this.getWebSocketForResponseID(id),\n (id) => this._requestIdToConnectionId.delete(id)\n );\n await server.connect(this._transport);\n }\n\n // This session must always use the streamable-http transport\n await this.ctx.storage.put(\"transportType\", \"streamable-http\");\n this._transportType = \"streamable-http\";\n\n return this._agent.fetch(request);\n }\n default:\n return new Response(\n \"Internal Server Error: Expected /sse or /streamable-http path\",\n {\n status: 500\n }\n );\n }\n }\n\n getWebSocket() {\n const websockets = this.ctx.getWebSockets();\n if (websockets.length === 0) {\n return null;\n }\n return websockets[0];\n }\n\n getWebSocketForResponseID(id: string): WebSocket | null {\n const connectionId = this._requestIdToConnectionId.get(id);\n if (connectionId === undefined) {\n return null;\n }\n return this._agent.getConnection(connectionId) ?? null;\n }\n\n // All messages received here. This is currently never called\n async onMessage(connection: Connection, event: WSMessage) {\n // Since we address the DO via both the protocol and the session id,\n // this should never happen, but let's enforce it just in case\n if (this._transportType !== \"streamable-http\") {\n const err = new Error(\n \"Internal Server Error: Expected streamable-http protocol\"\n );\n this._transport?.onerror?.(err);\n return;\n }\n\n let message: JSONRPCMessage;\n try {\n // Ensure event is a string\n const data =\n typeof event === \"string\" ? event : new TextDecoder().decode(event);\n message = JSONRPCMessageSchema.parse(JSON.parse(data));\n } catch (error) {\n this._transport?.onerror?.(error as Error);\n return;\n }\n\n // Check if this is an elicitation response before passing to transport\n if (await this._handleElicitationResponse(message)) {\n return; // Message was handled by elicitation system\n }\n\n // We need to map every incoming message to the connection that it came in on\n // so that we can send relevant responses and notifications back on the same connection\n if (isJSONRPCRequest(message)) {\n this._requestIdToConnectionId.set(message.id.toString(), connection.id);\n }\n\n this._transport?.onmessage?.(message);\n }\n\n /**\n * Wait for elicitation response through storage polling\n */\n private async _waitForElicitationResponse(\n requestId: string\n ): Promise<ElicitResult> {\n const startTime = Date.now();\n const timeout = 60000; // 60 second timeout\n\n try {\n while (Date.now() - startTime < timeout) {\n // Check if response has been stored\n const response = await this.ctx.storage.get<ElicitResult>(\n `elicitation:response:${requestId}`\n );\n if (response) {\n // Immediately clean up both request and response\n await this.ctx.storage.delete(`elicitation:${requestId}`);\n await this.ctx.storage.delete(`elicitation:response:${requestId}`);\n return response;\n }\n\n // Sleep briefly before checking again\n await new Promise((resolve) => setTimeout(resolve, 100));\n }\n\n throw new Error(\"Elicitation request timed out\");\n } finally {\n // Always clean up on timeout or error\n await this.ctx.storage.delete(`elicitation:${requestId}`);\n await this.ctx.storage.delete(`elicitation:response:${requestId}`);\n }\n }\n\n /**\n * Handle elicitation responses */\n private async _handleElicitationResponse(\n message: JSONRPCMessage\n ): Promise<boolean> {\n // Check if this is a response to an elicitation request\n if (isJSONRPCResponse(message) && message.result) {\n const requestId = message.id?.toString();\n if (!requestId || !requestId.startsWith(\"elicit_\")) return false;\n\n // Check if we have a pending request for this ID\n const pendingRequest = await this.ctx.storage.get(\n `elicitation:${requestId}`\n );\n if (!pendingRequest) return false;\n\n // Store the response in durable storage\n await this.ctx.storage.put(\n `elicitation:response:${requestId}`,\n message.result as ElicitResult\n );\n return true;\n }\n\n // Check if this is an error response to an elicitation request\n if (isJSONRPCError(message)) {\n const requestId = message.id?.toString();\n if (!requestId || !requestId.startsWith(\"elicit_\")) return false;\n\n // Check if we have a pending request for this ID\n const pendingRequest = await this.ctx.storage.get(\n `elicitation:${requestId}`\n );\n if (!pendingRequest) return false;\n\n // Store error response\n const errorResult: ElicitResult = {\n action: \"cancel\",\n content: {\n error: message.error.message || \"Elicitation request failed\"\n }\n };\n await this.ctx.storage.put(\n `elicitation:response:${requestId}`,\n errorResult\n );\n return true;\n }\n\n return false;\n }\n\n // All messages received over SSE after the initial connection has been established\n // will be passed here\n async onSSEMcpMessage(\n _sessionId: string,\n messageBody: unknown\n ): Promise<Error | null> {\n if (this._status !== \"started\") {\n // This means the server \"woke up\" after hibernation\n // so we need to hydrate it again\n await this._initialize();\n }\n\n // Since we address the DO via both the protocol and the session id,\n // this should never happen, but let's enforce it just in case\n if (this._transportType !== \"sse\") {\n return new Error(\"Internal Server Error: Expected SSE protocol\");\n }\n\n try {\n let parsedMessage: JSONRPCMessage;\n try {\n parsedMessage = JSONRPCMessageSchema.parse(messageBody);\n } catch (error) {\n this._transport?.onerror?.(error as Error);\n throw error;\n }\n\n // Check if this is an elicitation response before passing to transport\n if (await this._handleElicitationResponse(parsedMessage)) {\n return null; // Message was handled by elicitation system\n }\n\n this._transport?.onmessage?.(parsedMessage);\n return null;\n } catch (error) {\n console.error(\"Error forwarding message to SSE:\", error);\n this._transport?.onerror?.(error as Error);\n return error as Error;\n }\n }\n\n // Delegate all websocket events to the underlying agent\n async webSocketMessage(\n ws: WebSocket,\n event: ArrayBuffer | string\n ): Promise<void> {\n if (this._status !== \"started\") {\n // This means the server \"woke up\" after hibernation\n // so we need to hydrate it again\n await this._initialize();\n }\n return await this._agent.webSocketMessage(ws, event);\n }\n\n // WebSocket event handlers for hibernation support\n async webSocketError(ws: WebSocket, error: unknown): Promise<void> {\n if (this._status !== \"started\") {\n // This means the server \"woke up\" after hibernation\n // so we need to hydrate it again\n await this._initialize();\n }\n return await this._agent.webSocketError(ws, error);\n }\n\n async webSocketClose(\n ws: WebSocket,\n code: number,\n reason: string,\n wasClean: boolean\n ): Promise<void> {\n if (this._status !== \"started\") {\n // This means the server \"woke up\" after hibernation\n // so we need to hydrate it again\n await this._initialize();\n }\n return await this._agent.webSocketClose(ws, code, reason, wasClean);\n }\n\n static mount(\n path: string,\n {\n binding = \"MCP_OBJECT\",\n corsOptions\n }: {\n binding?: string;\n corsOptions?: CORSOptions;\n } = {}\n ) {\n return McpAgent.serveSSE(path, { binding, corsOptions });\n }\n\n static serveSSE(\n path: string,\n {\n binding = \"MCP_OBJECT\",\n corsOptions\n }: {\n binding?: string;\n corsOptions?: CORSOptions;\n } = {}\n ) {\n let pathname = path;\n if (path === \"/\") {\n pathname = \"/*\";\n }\n const basePattern = new URLPattern({ pathname });\n const messagePattern = new URLPattern({ pathname: `${pathname}/message` });\n\n return {\n async fetch<Env>(\n this: void,\n request: Request,\n env: Env,\n ctx: ExecutionContext\n ): Promise<Response> {\n // Handle CORS preflight\n const corsResponse = handleCORS(request, corsOptions);\n if (corsResponse) return corsResponse;\n\n const url = new URL(request.url);\n const bindingValue = env[binding as keyof typeof env] as unknown;\n\n // Ensure we have a binding of some sort\n if (bindingValue == null || typeof bindingValue !== \"object\") {\n console.error(\n `Could not find McpAgent binding for ${binding}. Did you update your wrangler configuration?`\n );\n return new Response(\"Invalid binding\", { status: 500 });\n }\n\n // Ensure that the binding is to a DurableObject\n if (!isDurableObjectNamespace(bindingValue)) {\n return new Response(\"Invalid binding\", { status: 500 });\n }\n\n const namespace =\n bindingValue satisfies DurableObjectNamespace<McpAgent>;\n\n // Handle initial SSE connection\n if (request.method === \"GET\" && basePattern.test(url)) {\n // Use a session ID if one is passed in, or create a unique\n // session ID for this connection\n const sessionId =\n url.searchParams.get(\"sessionId\") ||\n namespace.newUniqueId().toString();\n\n // Create a Transform Stream for SSE\n const { readable, writable } = new TransformStream();\n const writer = writable.getWriter();\n const encoder = new TextEncoder();\n\n // Send the endpoint event\n const endpointUrl = new URL(request.url);\n endpointUrl.pathname = encodeURI(`${pathname}/message`);\n endpointUrl.searchParams.set(\"sessionId\", sessionId);\n const relativeUrlWithSession =\n endpointUrl.pathname + endpointUrl.search + endpointUrl.hash;\n const endpointMessage = `event: endpoint\\ndata: ${relativeUrlWithSession}\\n\\n`;\n writer.write(encoder.encode(endpointMessage));\n\n // Get the Durable Object\n const id = namespace.idFromName(`sse:${sessionId}`);\n const doStub = namespace.get(id);\n\n // Initialize the object\n try {\n await doStub._init(ctx.props);\n } catch (error) {\n console.error(\"Failed to initialize McpAgent:\", error);\n await writer.close();\n const errorMessage =\n error instanceof Error ? error.message : String(error);\n return new Response(`Initialization failed: ${errorMessage}`, {\n status: 500\n });\n }\n\n // Connect to the Durable Object via WebSocket\n const upgradeUrl = new URL(request.url);\n // enforce that the path that the DO receives is always /sse\n upgradeUrl.pathname = \"/sse\";\n const existingHeaders: Record<string, string> = {};\n request.headers.forEach((value, key) => {\n existingHeaders[key] = value;\n });\n const response = await doStub.fetch(\n new Request(upgradeUrl, {\n headers: {\n ...existingHeaders,\n Upgrade: \"websocket\",\n // Required by PartyServer\n \"x-partykit-room\": sessionId\n }\n })\n );\n\n // Get the WebSocket\n const ws = response.webSocket;\n if (!ws) {\n console.error(\"Failed to establish WebSocket connection\");\n await writer.close();\n return new Response(\"Failed to establish WebSocket connection\", {\n status: 500\n });\n }\n\n // Accept the WebSocket\n ws.accept();\n\n // Handle messages from the Durable Object\n ws.addEventListener(\"message\", (event) => {\n async function onMessage(event: MessageEvent) {\n try {\n const message = JSON.parse(event.data);\n\n // validate that the message is a valid JSONRPC message\n const result = JSONRPCMessageSchema.safeParse(message);\n if (!result.success) {\n // The message was not a valid JSONRPC message, so we will drop it\n // PartyKit will broadcast state change messages to all connected clients\n // and we need to filter those out so they are not passed to MCP clients\n return;\n }\n\n // Send the message as an SSE event\n const messageText = `event: message\\ndata: ${JSON.stringify(result.data)}\\n\\n`;\n await writer.write(encoder.encode(messageText));\n } catch (error) {\n console.error(\"Error forwarding message to SSE:\", error);\n }\n }\n onMessage(event).catch(console.error);\n });\n\n // Handle WebSocket errors\n ws.addEventListener(\"error\", (error) => {\n async function onError(_error: Event) {\n try {\n await writer.close();\n } catch (_e) {\n // Ignore errors when closing\n }\n }\n onError(error).catch(console.error);\n });\n\n // Handle WebSocket closure\n ws.addEventListener(\"close\", () => {\n async function onClose() {\n try {\n await writer.close();\n } catch (error) {\n console.error(\"Error closing SSE connection:\", error);\n }\n }\n onClose().catch(console.error);\n });\n\n // Return the SSE response\n return new Response(readable, {\n headers: {\n \"Cache-Control\": \"no-cache\",\n Connection: \"keep-alive\",\n \"Content-Type\": \"text/event-stream\",\n ...corsHeaders(request, corsOptions)\n }\n });\n }\n\n // Handle incoming MCP messages. These will be passed to McpAgent\n // but the response will be sent back via the open SSE connection\n // so we only need to return a 202 Accepted response for success\n if (request.method === \"POST\" && messagePattern.test(url)) {\n const sessionId = url.searchParams.get(\"sessionId\");\n if (!sessionId) {\n return new Response(\n `Missing sessionId. Expected POST to ${pathname} to initiate new one`,\n { status: 400 }\n );\n }\n\n const contentType = request.headers.get(\"content-type\") || \"\";\n if (!contentType.includes(\"application/json\")) {\n return new Response(`Unsupported content-type: ${contentType}`, {\n status: 400\n });\n }\n\n // check if the request body is too large\n const contentLength = Number.parseInt(\n request.headers.get(\"content-length\") || \"0\",\n 10\n );\n if (contentLength > MAXIMUM_MESSAGE_SIZE_BYTES) {\n return new Response(\n `Request body too large: ${contentLength} bytes`,\n {\n status: 400\n }\n );\n }\n\n // Get the Durable Object\n const id = namespace.idFromName(`sse:${sessionId}`);\n const doStub = namespace.get(id);\n\n const messageBody = await request.json();\n // Update props with fresh values before processing message\n await doStub.updateProps(ctx.props);\n const error = await doStub.onSSEMcpMessage(sessionId, messageBody);\n\n if (error) {\n return new Response(error.message, {\n headers: {\n \"Cache-Control\": \"no-cache\",\n Connection: \"keep-alive\",\n \"Content-Type\": \"text/event-stream\",\n ...corsHeaders(request, corsOptions)\n },\n status: 400\n });\n }\n\n return new Response(\"Accepted\", {\n headers: {\n \"Cache-Control\": \"no-cache\",\n Connection: \"keep-alive\",\n \"Content-Type\": \"text/event-stream\",\n ...corsHeaders(request, corsOptions)\n },\n status: 202\n });\n }\n\n return new Response(\"Not Found\", { status: 404 });\n }\n };\n }\n\n static serve(\n path: string,\n {\n binding = \"MCP_OBJECT\",\n corsOptions\n }: { binding?: string; corsOptions?: CORSOptions } = {}\n ) {\n let pathname = path;\n if (path === \"/\") {\n pathname = \"/*\";\n }\n const basePattern = new URLPattern({ pathname });\n\n return {\n async fetch<Env>(\n this: void,\n request: Request,\n env: Env,\n ctx: ExecutionContext\n ): Promise<Response> {\n // Handle CORS preflight\n const corsResponse = handleCORS(request, corsOptions);\n if (corsResponse) {\n return corsResponse;\n }\n\n const url = new URL(request.url);\n const bindingValue = env[binding as keyof typeof env] as unknown;\n\n // Ensure we have a binding of some sort\n if (bindingValue == null || typeof bindingValue !== \"object\") {\n console.error(\n `Could not find McpAgent binding for ${binding}. Did you update your wrangler configuration?`\n );\n return new Response(\"Invalid binding\", { status: 500 });\n }\n\n // Ensure that the binding is to a DurableObject\n if (!isDurableObjectNamespace(bindingValue)) {\n return new Response(\"Invalid binding\", { status: 500 });\n }\n\n const namespace =\n bindingValue satisfies DurableObjectNamespace<McpAgent>;\n\n if (request.method === \"POST\" && basePattern.test(url)) {\n // validate the Accept header\n const acceptHeader = request.headers.get(\"accept\");\n // The client MUST include an Accept header, listing both application/json and text/event-stream as supported content types.\n if (\n !acceptHeader?.includes(\"application/json\") ||\n !acceptHeader.includes(\"text/event-stream\")\n ) {\n const body = JSON.stringify({\n error: {\n code: -32000,\n message:\n \"Not Acceptable: Client must accept both application/json and text/event-stream\"\n },\n id: null,\n jsonrpc: \"2.0\"\n });\n return new Response(body, { status: 406 });\n }\n\n const ct = request.headers.get(\"content-type\");\n if (!ct || !ct.includes(\"application/json\")) {\n const body = JSON.stringify({\n error: {\n code: -32000,\n message:\n \"Unsupported Media Type: Content-Type must be application/json\"\n },\n id: null,\n jsonrpc: \"2.0\"\n });\n return new Response(body, { status: 415 });\n }\n\n // Check content length against maximum allowed size\n const contentLength = Number.parseInt(\n request.headers.get(\"content-length\") ?? \"0\",\n 10\n );\n if (contentLength > MAXIMUM_MESSAGE_SIZE_BYTES) {\n const body = JSON.stringify({\n error: {\n code: -32000,\n message: `Request body too large. Maximum size is ${MAXIMUM_MESSAGE_SIZE_BYTES} bytes`\n },\n id: null,\n jsonrpc: \"2.0\"\n });\n return new Response(body, { status: 413 });\n }\n\n let sessionId = request.headers.get(\"mcp-session-id\");\n let rawMessage: unknown;\n\n try {\n rawMessage = await request.json();\n } catch (_error) {\n const body = JSON.stringify({\n error: {\n code: -32700,\n message: \"Parse error: Invalid JSON\"\n },\n id: null,\n jsonrpc: \"2.0\"\n });\n return new Response(body, { status: 400 });\n }\n\n // Make sure the message is an array to simplify logic\n let arrayMessage: unknown[];\n if (Array.isArray(rawMessage)) {\n arrayMessage = rawMessage;\n } else {\n arrayMessage = [rawMessage];\n }\n\n let messages: JSONRPCMessage[] = [];\n\n // Try to parse each message as JSON RPC. Fail if any message is invalid\n for (const msg of arrayMessage) {\n if (!JSONRPCMessageSchema.safeParse(msg).success) {\n const body = JSON.stringify({\n error: {\n code: -32700,\n message: \"Parse error: Invalid JSON-RPC message\"\n },\n id: null,\n jsonrpc: \"2.0\"\n });\n return new Response(body, { status: 400 });\n }\n }\n\n messages = arrayMessage.map((msg) => JSONRPCMessageSchema.parse(msg));\n\n // Before we pass the messages to the agent, there's another error condition we need to enforce\n // Check if this is an initialization request\n // https://spec.modelcontextprotocol.io/specification/2025-03-26/basic/lifecycle/\n const isInitializationRequest = messages.some(\n (msg) => InitializeRequestSchema.safeParse(msg).success\n );\n\n if (isInitializationRequest && sessionId) {\n const body = JSON.stringify({\n error: {\n code: -32600,\n message:\n \"Invalid Request: Initialization requests must not include a sessionId\"\n },\n id: null,\n jsonrpc: \"2.0\"\n });\n return new Response(body, { status: 400 });\n }\n\n // The initialization request must be the only request in the batch\n if (isInitializationRequest && messages.length > 1) {\n const body = JSON.stringify({\n error: {\n code: -32600,\n message:\n \"Invalid Request: Only one initialization request is allowed\"\n },\n id: null,\n jsonrpc: \"2.0\"\n });\n return new Response(body, { status: 400 });\n }\n\n // If an Mcp-Session-Id is returned by the server during initialization,\n // clients using the Streamable HTTP transport MUST include it\n // in the Mcp-Session-Id header on all of their subsequent HTTP requests.\n if (!isInitializationRequest && !sessionId) {\n const body = JSON.stringify({\n error: {\n code: -32000,\n message: \"Bad Request: Mcp-Session-Id header is required\"\n },\n id: null,\n jsonrpc: \"2.0\"\n });\n return new Response(body, { status: 400 });\n }\n\n // If we don't have a sessionId, we are serving an initialization request\n // and need to generate a new sessionId\n sessionId = sessionId ?? namespace.newUniqueId().toString();\n\n // fetch the agent DO\n const id = namespace.idFromName(`streamable-http:${sessionId}`);\n const doStub = namespace.get(id);\n const isInitialized = await doStub.isInitialized();\n\n if (isInitializationRequest) {\n try {\n await doStub._init(ctx.props);\n await doStub.setInitialized();\n } catch (error) {\n console.error(\"Failed to initialize McpAgent:\", error);\n const errorMessage =\n error instanceof Error ? error.message : String(error);\n const body = JSON.stringify({\n error: {\n code: -32001,\n message: `Initialization failed: ${errorMessage}`\n },\n id: null,\n jsonrpc: \"2.0\"\n });\n return new Response(body, { status: 500 });\n }\n } else if (!isInitialized) {\n // if we have gotten here, then a session id that was never initialized\n // was provided\n const body = JSON.stringify({\n error: {\n code: -32001,\n message: \"Session not found\"\n },\n id: null,\n jsonrpc: \"2.0\"\n });\n return new Response(body, { status: 404 });\n } else {\n // Update props for existing sessions\n await doStub.updateProps(ctx.props);\n }\n\n // We've evaluated all the error conditions! Now it's time to establish\n // all the streams\n\n // Create a Transform Stream for SSE\n const { readable, writable } = new TransformStream();\n const writer = writable.getWriter();\n const encoder = new TextEncoder();\n\n // Connect to the Durable Object via WebSocket\n const upgradeUrl = new URL(request.url);\n upgradeUrl.pathname = \"/streamable-http\";\n const existingHeaders: Record<string, string> = {};\n request.headers.forEach((value, key) => {\n existingHeaders[key] = value;\n });\n const response = await doStub.fetch(\n new Request(upgradeUrl, {\n headers: {\n ...existingHeaders,\n Upgrade: \"websocket\",\n // Required by PartyServer\n \"x-partykit-room\": sessionId\n }\n })\n );\n\n // Get the WebSocket\n const ws = response.webSocket;\n if (!ws) {\n console.error(\"Failed to establish WebSocket connection\");\n\n await writer.close();\n const body = JSON.stringify({\n error: {\n code: -32001,\n message: \"Failed to establish WebSocket connection\"\n },\n id: null,\n jsonrpc: \"2.0\"\n });\n return new Response(body, { status: 500 });\n }\n\n // Keep track of the request ids that we have sent to the server\n // so that we can close the connection once we have received\n // all the responses\n const requestIds: Set<string | number> = new Set();\n\n // Accept the WebSocket\n ws.accept();\n\n // Handle messages from the Durable Object\n ws.addEventListener(\"message\", (event) => {\n async function onMessage(event: MessageEvent) {\n try {\n const data =\n typeof event.data === \"string\"\n ? event.data\n : new TextDecoder().decode(event.data);\n const message = JSON.parse(data);\n\n // validate that the message is a valid JSONRPC message\n const result = JSONRPCMessageSchema.safeParse(message);\n if (!result.success) {\n // The message was not a valid JSONRPC message, so we will drop it\n // PartyKit will broadcast state change messages to all connected clients\n // and we need to filter those out so they are not passed to MCP clients\n return;\n }\n\n // If the message is a response or an error, remove the id from the set of\n // request ids\n if (\n isJSONRPCResponse(result.data) ||\n isJSONRPCError(result.data)\n ) {\n requestIds.delete(result.data.id);\n }\n\n // Send the message as an SSE event\n const messageText = `event: message\\ndata: ${JSON.stringify(result.data)}\\n\\n`;\n await writer.write(encoder.encode(messageText));\n\n // If we have received all the responses, close the connection\n if (requestIds.size === 0) {\n ws!.close();\n }\n } catch (error) {\n console.error(\"Error forwarding message to SSE:\", error);\n }\n }\n onMessage(event).catch(console.error);\n });\n\n // Handle WebSocket errors\n ws.addEventListener(\"error\", (error) => {\n async function onError(_error: Event) {\n try {\n await writer.close();\n } catch (_e) {\n // Ignore errors when closing\n }\n }\n onError(error).catch(console.error);\n });\n\n // Handle WebSocket closure\n ws.addEventListener(\"close\", () => {\n async function onClose() {\n try {\n await writer.close();\n } catch (error) {\n console.error(\"Error closing SSE connection:\", error);\n }\n }\n onClose().catch(console.error);\n });\n\n // If there are no requests, we send the messages to the agent and acknowledge the request with a 202\n // since we don't expect any responses back through this connection\n const hasOnlyNotificationsOrResponses = messages.every(\n (msg) => isJSONRPCNotification(msg) || isJSONRPCResponse(msg)\n );\n if (hasOnlyNotificationsOrResponses) {\n for (const message of messages) {\n ws.send(JSON.stringify(message));\n }\n\n // closing the websocket will also close the SSE connection\n ws.close();\n\n return new Response(null, {\n headers: corsHeaders(request, corsOptions),\n status: 202\n });\n }\n\n for (const message of messages) {\n if (isJSONRPCRequest(message)) {\n // add each request id that we send off to a set\n // so that we can keep track of which requests we\n // still need a response for\n requestIds.add(message.id);\n }\n ws.send(JSON.stringify(message));\n }\n\n // Return the SSE response. We handle closing the stream in the ws \"message\"\n // handler\n return new Response(readable, {\n headers: {\n \"Cache-Control\": \"no-cache\",\n Connection: \"keep-alive\",\n \"Content-Type\": \"text/event-stream\",\n \"mcp-session-id\": sessionId,\n ...corsHeaders(request, corsOptions)\n },\n status: 200\n });\n }\n\n // We don't yet support GET or DELETE requests\n const body = JSON.stringify({\n error: {\n code: -32000,\n message: \"Method not allowed\"\n },\n id: null,\n jsonrpc: \"2.0\"\n });\n return new Response(body, { status: 405 });\n }\n };\n }\n}\n\n// Export client transport classes\nexport { SSEEdgeClientTransport } from \"./sse-edge\";\nexport { StreamableHTTPEdgeClientTransport } from \"./streamable-http-edge\";\n\n// Export elicitation types and schemas\nexport {\n ElicitRequestSchema,\n type ElicitRequest,\n type ElicitResult\n} from \"@modelcontextprotocol/sdk/types.js\";\n"],"mappings":"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","names":["event","body"]}
@@ -1,12 +1,14 @@
1
1
  import 'ai';
2
- export { b as Observability, O as ObservabilityEvent, g as genericObservability } from '../index-BIJvkfYt.js';
2
+ export { b as Observability, O as ObservabilityEvent, g as genericObservability } from '../index-BCJclX6q.js';
3
+ import 'cloudflare:workers';
3
4
  import '@modelcontextprotocol/sdk/client/index.js';
4
5
  import '@modelcontextprotocol/sdk/types.js';
5
6
  import 'partyserver';
6
- import '../mcp/client.js';
7
+ import '../client-DgyzBU_8.js';
7
8
  import 'zod';
8
- import '@modelcontextprotocol/sdk/client/sse.js';
9
9
  import '@modelcontextprotocol/sdk/shared/protocol.js';
10
+ import '@modelcontextprotocol/sdk/client/sse.js';
11
+ import '@modelcontextprotocol/sdk/client/streamableHttp.js';
10
12
  import '../mcp/do-oauth-client-provider.js';
11
13
  import '@modelcontextprotocol/sdk/client/auth.js';
12
14
  import '@modelcontextprotocol/sdk/shared/auth.js';
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  genericObservability
3
- } from "../chunk-5YIRLLUX.js";
4
- import "../chunk-MW5BQ2FW.js";
3
+ } from "../chunk-JXN5WZFQ.js";
4
+ import "../chunk-HY7ZLHJB.js";
5
5
  import "../chunk-PVQZBKN7.js";
6
6
  import "../chunk-KUH345EY.js";
7
7
  export {
package/dist/react.d.ts CHANGED
@@ -1,16 +1,18 @@
1
1
  import { PartySocket } from "partysocket";
2
2
  import { usePartySocket } from "partysocket/react";
3
- import { M as MCPServersState, A as Agent } from "./index-BIJvkfYt.js";
3
+ import { M as MCPServersState, A as Agent } from "./index-BCJclX6q.js";
4
4
  import { StreamOptions } from "./client.js";
5
5
  import { Method, RPCMethod } from "./serializable.js";
6
+ import "cloudflare:workers";
6
7
  import "@modelcontextprotocol/sdk/client/index.js";
7
8
  import "@modelcontextprotocol/sdk/types.js";
8
9
  import "partyserver";
9
- import "./mcp/client.js";
10
+ import "./client-DgyzBU_8.js";
10
11
  import "zod";
11
- import "@modelcontextprotocol/sdk/client/sse.js";
12
12
  import "@modelcontextprotocol/sdk/shared/protocol.js";
13
13
  import "ai";
14
+ import "@modelcontextprotocol/sdk/client/sse.js";
15
+ import "@modelcontextprotocol/sdk/client/streamableHttp.js";
14
16
  import "./mcp/do-oauth-client-provider.js";
15
17
  import "@modelcontextprotocol/sdk/client/auth.js";
16
18
  import "@modelcontextprotocol/sdk/shared/auth.js";
@@ -16,15 +16,15 @@ declare const unstable_scheduleSchema: z.ZodObject<
16
16
  z.ZodTypeAny,
17
17
  {
18
18
  type: "scheduled" | "delayed" | "cron" | "no-schedule";
19
+ date?: Date | undefined;
19
20
  delayInSeconds?: number | undefined;
20
21
  cron?: string | undefined;
21
- date?: Date | undefined;
22
22
  },
23
23
  {
24
24
  type: "scheduled" | "delayed" | "cron" | "no-schedule";
25
+ date?: Date | undefined;
25
26
  delayInSeconds?: number | undefined;
26
27
  cron?: string | undefined;
27
- date?: Date | undefined;
28
28
  }
29
29
  >;
30
30
  },
@@ -34,18 +34,18 @@ declare const unstable_scheduleSchema: z.ZodObject<
34
34
  description: string;
35
35
  when: {
36
36
  type: "scheduled" | "delayed" | "cron" | "no-schedule";
37
+ date?: Date | undefined;
37
38
  delayInSeconds?: number | undefined;
38
39
  cron?: string | undefined;
39
- date?: Date | undefined;
40
40
  };
41
41
  },
42
42
  {
43
43
  description: string;
44
44
  when: {
45
45
  type: "scheduled" | "delayed" | "cron" | "no-schedule";
46
+ date?: Date | undefined;
46
47
  delayInSeconds?: number | undefined;
47
48
  cron?: string | undefined;
48
- date?: Date | undefined;
49
49
  };
50
50
  }
51
51
  >;
package/package.json CHANGED
@@ -4,19 +4,22 @@
4
4
  "url": "https://github.com/cloudflare/agents/issues"
5
5
  },
6
6
  "dependencies": {
7
- "@modelcontextprotocol/sdk": "^1.13.3",
8
- "ai": "^4.3.16",
7
+ "@modelcontextprotocol/sdk": "^1.17.1",
8
+ "ai": "^4.3.19",
9
9
  "cron-schedule": "^5.0.4",
10
10
  "mimetext": "^3.0.27",
11
11
  "nanoid": "^5.1.5",
12
12
  "partyserver": "^0.0.72",
13
- "partysocket": "1.1.4",
13
+ "partysocket": "1.1.5",
14
14
  "zod": "^3.25.67"
15
15
  },
16
+ "publishConfig": {
17
+ "access": "public"
18
+ },
16
19
  "description": "A home for your AI agents",
17
20
  "devDependencies": {
18
21
  "react": "*",
19
- "vitest-browser-react": "^1.0.0"
22
+ "vitest-browser-react": "^1.0.1"
20
23
  },
21
24
  "exports": {
22
25
  ".": {
@@ -102,5 +105,5 @@
102
105
  },
103
106
  "type": "module",
104
107
  "types": "dist/index.d.ts",
105
- "version": "0.0.0-e48e5f9"
108
+ "version": "0.0.0-e934f53"
106
109
  }
package/src/index.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import type { env } from "cloudflare:workers";
1
2
  import { AsyncLocalStorage } from "node:async_hooks";
2
3
  import type { Client } from "@modelcontextprotocol/sdk/client/index.js";
3
4
  import type { SSEClientTransportOptions } from "@modelcontextprotocol/sdk/client/sse.js";
@@ -283,7 +284,7 @@ function withAgentContext<T extends (...args: any[]) => any>(
283
284
  * @template Env Environment type containing bindings
284
285
  * @template State State type to store within the Agent
285
286
  */
286
- export class Agent<Env, State = unknown> extends Server<Env> {
287
+ export class Agent<Env = typeof env, State = unknown> extends Server<Env> {
287
288
  private _state = DEFAULT_STATE as State;
288
289
 
289
290
  private _ParentClass: typeof Agent<Env, State> =
@@ -606,15 +607,22 @@ export class Agent<Env, State = unknown> extends Server<Env> {
606
607
  email: undefined
607
608
  },
608
609
  async () => {
609
- const servers = this.sql<MCPServerRow>`
610
+ await this._tryCatch(() => {
611
+ const servers = this.sql<MCPServerRow>`
610
612
  SELECT id, name, server_url, client_id, auth_url, callback_url, server_options FROM cf_agents_mcp_servers;
611
613
  `;
612
614
 
613
- // from DO storage, reconnect to all servers not currently in the oauth flow using our saved auth information
614
- if (servers && Array.isArray(servers) && servers.length > 0) {
615
- Promise.allSettled(
616
- servers.map((server) => {
617
- return this._connectToMcpServerInternal(
615
+ this.broadcast(
616
+ JSON.stringify({
617
+ mcp: this.getMcpServers(),
618
+ type: "cf_agent_mcp_servers"
619
+ })
620
+ );
621
+
622
+ // from DO storage, reconnect to all servers not currently in the oauth flow using our saved auth information
623
+ if (servers && Array.isArray(servers) && servers.length > 0) {
624
+ servers.forEach((server) => {
625
+ this._connectToMcpServerInternal(
618
626
  server.name,
619
627
  server.server_url,
620
628
  server.callback_url,
@@ -625,18 +633,33 @@ export class Agent<Env, State = unknown> extends Server<Env> {
625
633
  id: server.id,
626
634
  oauthClientId: server.client_id ?? undefined
627
635
  }
628
- );
629
- })
630
- ).then((_results) => {
631
- this.broadcast(
632
- JSON.stringify({
633
- mcp: this.getMcpServers(),
634
- type: "cf_agent_mcp_servers"
635
- })
636
- );
637
- });
638
- }
639
- await this._tryCatch(() => _onStart());
636
+ )
637
+ .then(() => {
638
+ // Broadcast updated MCP servers state after each server connects
639
+ this.broadcast(
640
+ JSON.stringify({
641
+ mcp: this.getMcpServers(),
642
+ type: "cf_agent_mcp_servers"
643
+ })
644
+ );
645
+ })
646
+ .catch((error) => {
647
+ console.error(
648
+ `Error connecting to MCP server: ${server.name} (${server.server_url})`,
649
+ error
650
+ );
651
+ // Still broadcast even if connection fails, so clients know about the failure
652
+ this.broadcast(
653
+ JSON.stringify({
654
+ mcp: this.getMcpServers(),
655
+ type: "cf_agent_mcp_servers"
656
+ })
657
+ );
658
+ });
659
+ });
660
+ }
661
+ return _onStart();
662
+ });
640
663
  }
641
664
  );
642
665
  };
@@ -927,7 +950,6 @@ export class Agent<Env, State = unknown> extends Server<Env> {
927
950
  }
928
951
  this._flushingQueue = true;
929
952
  while (true) {
930
- const executed: string[] = [];
931
953
  const result = this.sql<QueueItem<string>>`
932
954
  SELECT * FROM cf_agents_queues
933
955
  ORDER BY created_at ASC
@@ -959,13 +981,10 @@ export class Agent<Env, State = unknown> extends Server<Env> {
959
981
  queueItem: QueueItem<string>
960
982
  ) => Promise<void>
961
983
  ).bind(this)(JSON.parse(row.payload as string), row);
962
- executed.push(row.id);
984
+ await this.dequeue(row.id);
963
985
  }
964
986
  );
965
987
  }
966
- for (const id of executed) {
967
- await this.dequeue(id);
968
- }
969
988
  }
970
989
  this._flushingQueue = false;
971
990
  }
@@ -1226,9 +1245,9 @@ export class Agent<Env, State = unknown> extends Server<Env> {
1226
1245
  private async _scheduleNextAlarm() {
1227
1246
  // Find the next schedule that needs to be executed
1228
1247
  const result = this.sql`
1229
- SELECT time FROM cf_agents_schedules
1248
+ SELECT time FROM cf_agents_schedules
1230
1249
  WHERE time > ${Math.floor(Date.now() / 1000)}
1231
- ORDER BY time ASC
1250
+ ORDER BY time ASC
1232
1251
  LIMIT 1
1233
1252
  `;
1234
1253
  if (!result) return;
@@ -1696,6 +1715,13 @@ export type EmailRoutingOptions<Env> = AgentOptions<Env> & {
1696
1715
  resolver: EmailResolver<Env>;
1697
1716
  };
1698
1717
 
1718
+ // Cache the agent namespace map for email routing
1719
+ // This maps both kebab-case and original names to namespaces
1720
+ const agentMapCache = new WeakMap<
1721
+ Record<string, unknown>,
1722
+ Record<string, unknown>
1723
+ >();
1724
+
1699
1725
  /**
1700
1726
  * Route an email to the appropriate Agent
1701
1727
  * @param email The email to route
@@ -1715,28 +1741,41 @@ export async function routeAgentEmail<Env>(
1715
1741
  return;
1716
1742
  }
1717
1743
 
1718
- const namespaceBinding = env[routingInfo.agentName as keyof Env];
1719
- if (!namespaceBinding) {
1720
- throw new Error(
1721
- `Agent namespace '${routingInfo.agentName}' not found in environment`
1722
- );
1744
+ // Build a map that includes both original names and kebab-case versions
1745
+ if (!agentMapCache.has(env as Record<string, unknown>)) {
1746
+ const map: Record<string, unknown> = {};
1747
+ for (const [key, value] of Object.entries(env as Record<string, unknown>)) {
1748
+ if (
1749
+ value &&
1750
+ typeof value === "object" &&
1751
+ "idFromName" in value &&
1752
+ typeof value.idFromName === "function"
1753
+ ) {
1754
+ // Add both the original name and kebab-case version
1755
+ map[key] = value;
1756
+ map[camelCaseToKebabCase(key)] = value;
1757
+ }
1758
+ }
1759
+ agentMapCache.set(env as Record<string, unknown>, map);
1723
1760
  }
1724
1761
 
1725
- // Type guard to check if this is actually a DurableObjectNamespace (AgentNamespace)
1726
- if (
1727
- typeof namespaceBinding !== "object" ||
1728
- !("idFromName" in namespaceBinding) ||
1729
- typeof namespaceBinding.idFromName !== "function"
1730
- ) {
1762
+ const agentMap = agentMapCache.get(env as Record<string, unknown>)!;
1763
+ const namespace = agentMap[routingInfo.agentName];
1764
+
1765
+ if (!namespace) {
1766
+ // Provide helpful error message listing available agents
1767
+ const availableAgents = Object.keys(agentMap)
1768
+ .filter((key) => !key.includes("-")) // Show only original names, not kebab-case duplicates
1769
+ .join(", ");
1731
1770
  throw new Error(
1732
- `Environment binding '${routingInfo.agentName}' is not an AgentNamespace (found: ${typeof namespaceBinding})`
1771
+ `Agent namespace '${routingInfo.agentName}' not found in environment. Available agents: ${availableAgents}`
1733
1772
  );
1734
1773
  }
1735
1774
 
1736
- // Safe cast after runtime validation
1737
- const namespace = namespaceBinding as unknown as AgentNamespace<Agent<Env>>;
1738
-
1739
- const agent = await getAgentByName(namespace, routingInfo.agentId);
1775
+ const agent = await getAgentByName(
1776
+ namespace as unknown as AgentNamespace<Agent<Env>>,
1777
+ routingInfo.agentId
1778
+ );
1740
1779
 
1741
1780
  // let's make a serialisable version of the email
1742
1781
  const serialisableEmail: AgentEmail = {