agents 0.0.61 → 0.0.63

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.
package/dist/ai-react.js CHANGED
@@ -157,11 +157,7 @@ function useAgentChat(options) {
157
157
  agent.removeEventListener("message", onClearHistory);
158
158
  agent.removeEventListener("message", onMessages);
159
159
  };
160
- }, [
161
- agent.addEventListener,
162
- agent.removeEventListener,
163
- useChatHelpers.setMessages
164
- ]);
160
+ }, [agent, useChatHelpers.setMessages]);
165
161
  return {
166
162
  ...useChatHelpers,
167
163
  /**
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/ai-react.tsx"],"sourcesContent":["import { useChat } from \"@ai-sdk/react\";\nimport type { Message } from \"ai\";\nimport type { useAgent } from \"./react\";\nimport { useEffect, use } from \"react\";\nimport type { OutgoingMessage } from \"./ai-types\";\n\ntype GetInitialMessagesOptions = {\n agent: string;\n name: string;\n url: string;\n};\n\n/**\n * Options for the useAgentChat hook\n */\ntype UseAgentChatOptions<State> = Omit<\n Parameters<typeof useChat>[0] & {\n /** Agent connection from useAgent */\n agent: ReturnType<typeof useAgent<State>>;\n getInitialMessages?:\n | undefined\n | null\n // | (() => Message[])\n | ((options: GetInitialMessagesOptions) => Promise<Message[]>);\n },\n \"fetch\"\n>;\n\n// TODO: clear cache when the agent is unmounted?\nconst requestCache = new Map<string, Promise<Message[]>>();\n\n/**\n * React hook for building AI chat interfaces using an Agent\n * @param options Chat options including the agent connection\n * @returns Chat interface controls and state with added clearHistory method\n */\nexport function useAgentChat<State = unknown>(\n options: UseAgentChatOptions<State>\n) {\n const { agent, getInitialMessages, ...rest } = options;\n\n const agentUrl = new URL(\n `${// @ts-expect-error we're using a protected _url property that includes query params\n ((agent._url as string | null) || agent._pkurl)\n ?.replace(\"ws://\", \"http://\")\n .replace(\"wss://\", \"https://\")}`\n );\n\n // delete the _pk query param\n agentUrl.searchParams.delete(\"_pk\");\n const agentUrlString = agentUrl.toString();\n\n async function defaultGetInitialMessagesFetch({\n url,\n }: GetInitialMessagesOptions) {\n const getMessagesUrl = new URL(url);\n getMessagesUrl.pathname += \"/get-messages\";\n const response = await fetch(getMessagesUrl.toString(), {\n headers: options.headers,\n credentials: options.credentials,\n });\n return response.json<Message[]>();\n }\n\n const getInitialMessagesFetch =\n getInitialMessages || defaultGetInitialMessagesFetch;\n\n function doGetInitialMessages(\n getInitialMessagesOptions: GetInitialMessagesOptions\n ) {\n if (requestCache.has(agentUrlString)) {\n return requestCache.get(agentUrlString)!;\n }\n const promise = getInitialMessagesFetch(getInitialMessagesOptions);\n requestCache.set(agentUrlString, promise);\n return promise;\n }\n\n const initialMessages =\n getInitialMessages !== null\n ? use(\n doGetInitialMessages({\n agent: agent.agent,\n name: agent.name,\n url: agentUrlString,\n })\n )\n : rest.initialMessages;\n\n useEffect(() => {\n return () => {\n requestCache.delete(agentUrlString);\n };\n }, [agentUrlString]);\n\n async function aiFetch(\n request: RequestInfo | URL,\n options: RequestInit = {}\n ) {\n // we're going to use a websocket to do the actual \"fetching\"\n // but still satisfy the type signature of the fetch function\n // so we'll return a promise that resolves to a response\n\n const {\n method,\n keepalive,\n headers,\n body,\n redirect,\n integrity,\n signal,\n credentials,\n mode,\n referrer,\n referrerPolicy,\n window,\n // dispatcher, duplex\n } = options;\n const id = crypto.randomUUID();\n const abortController = new AbortController();\n\n signal?.addEventListener(\"abort\", () => {\n abortController.abort();\n });\n\n agent.addEventListener(\n \"message\",\n (event) => {\n let data: OutgoingMessage;\n try {\n data = JSON.parse(event.data) as OutgoingMessage;\n } catch (error) {\n // silently ignore invalid messages for now\n // TODO: log errors with log levels\n return;\n }\n if (data.type === \"cf_agent_use_chat_response\") {\n if (data.id === id) {\n controller.enqueue(new TextEncoder().encode(data.body));\n if (data.done) {\n controller.close();\n abortController.abort();\n }\n }\n }\n },\n { signal: abortController.signal }\n );\n\n let controller: ReadableStreamDefaultController;\n\n const stream = new ReadableStream({\n start(c) {\n controller = c;\n },\n });\n\n agent.send(\n JSON.stringify({\n type: \"cf_agent_use_chat_request\",\n id,\n url: request.toString(),\n init: {\n method,\n keepalive,\n headers,\n body,\n redirect,\n integrity,\n credentials,\n mode,\n referrer,\n referrerPolicy,\n window,\n // dispatcher,\n // duplex\n },\n })\n );\n\n return new Response(stream);\n }\n const useChatHelpers = useChat({\n initialMessages,\n sendExtraMessageFields: true,\n fetch: aiFetch,\n ...rest,\n });\n\n useEffect(() => {\n function onClearHistory(event: MessageEvent) {\n if (typeof event.data !== \"string\") {\n return;\n }\n let data: OutgoingMessage;\n try {\n data = JSON.parse(event.data) as OutgoingMessage;\n } catch (error) {\n // silently ignore invalid messages for now\n // TODO: log errors with log levels\n return;\n }\n if (data.type === \"cf_agent_chat_clear\") {\n useChatHelpers.setMessages([]);\n }\n }\n\n function onMessages(event: MessageEvent) {\n if (typeof event.data !== \"string\") {\n return;\n }\n let data: OutgoingMessage;\n try {\n data = JSON.parse(event.data) as OutgoingMessage;\n } catch (error) {\n // silently ignore invalid messages for now\n // TODO: log errors with log levels\n return;\n }\n if (data.type === \"cf_agent_chat_messages\") {\n useChatHelpers.setMessages(data.messages);\n }\n }\n\n agent.addEventListener(\"message\", onClearHistory);\n agent.addEventListener(\"message\", onMessages);\n\n return () => {\n agent.removeEventListener(\"message\", onClearHistory);\n agent.removeEventListener(\"message\", onMessages);\n };\n }, [\n agent.addEventListener,\n agent.removeEventListener,\n useChatHelpers.setMessages,\n ]);\n\n return {\n ...useChatHelpers,\n /**\n * Set the chat messages and synchronize with the Agent\n * @param messages New messages to set\n */\n setMessages: (messages: Message[]) => {\n useChatHelpers.setMessages(messages);\n agent.send(\n JSON.stringify({\n type: \"cf_agent_chat_messages\",\n messages,\n })\n );\n },\n /**\n * Clear chat history on both client and Agent\n */\n clearHistory: () => {\n useChatHelpers.setMessages([]);\n agent.send(\n JSON.stringify({\n type: \"cf_agent_chat_clear\",\n })\n );\n },\n };\n}\n"],"mappings":"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","names":["options"]}
1
+ {"version":3,"sources":["../src/ai-react.tsx"],"sourcesContent":["import { useChat } from \"@ai-sdk/react\";\nimport type { Message } from \"ai\";\nimport type { useAgent } from \"./react\";\nimport { useEffect, use } from \"react\";\nimport type { OutgoingMessage } from \"./ai-types\";\n\ntype GetInitialMessagesOptions = {\n agent: string;\n name: string;\n url: string;\n};\n\n/**\n * Options for the useAgentChat hook\n */\ntype UseAgentChatOptions<State> = Omit<\n Parameters<typeof useChat>[0] & {\n /** Agent connection from useAgent */\n agent: ReturnType<typeof useAgent<State>>;\n getInitialMessages?:\n | undefined\n | null\n // | (() => Message[])\n | ((options: GetInitialMessagesOptions) => Promise<Message[]>);\n },\n \"fetch\"\n>;\n\n// TODO: clear cache when the agent is unmounted?\nconst requestCache = new Map<string, Promise<Message[]>>();\n\n/**\n * React hook for building AI chat interfaces using an Agent\n * @param options Chat options including the agent connection\n * @returns Chat interface controls and state with added clearHistory method\n */\nexport function useAgentChat<State = unknown>(\n options: UseAgentChatOptions<State>\n) {\n const { agent, getInitialMessages, ...rest } = options;\n\n const agentUrl = new URL(\n `${// @ts-expect-error we're using a protected _url property that includes query params\n ((agent._url as string | null) || agent._pkurl)\n ?.replace(\"ws://\", \"http://\")\n .replace(\"wss://\", \"https://\")}`\n );\n\n // delete the _pk query param\n agentUrl.searchParams.delete(\"_pk\");\n const agentUrlString = agentUrl.toString();\n\n async function defaultGetInitialMessagesFetch({\n url,\n }: GetInitialMessagesOptions) {\n const getMessagesUrl = new URL(url);\n getMessagesUrl.pathname += \"/get-messages\";\n const response = await fetch(getMessagesUrl.toString(), {\n headers: options.headers,\n credentials: options.credentials,\n });\n return response.json<Message[]>();\n }\n\n const getInitialMessagesFetch =\n getInitialMessages || defaultGetInitialMessagesFetch;\n\n function doGetInitialMessages(\n getInitialMessagesOptions: GetInitialMessagesOptions\n ) {\n if (requestCache.has(agentUrlString)) {\n return requestCache.get(agentUrlString)!;\n }\n const promise = getInitialMessagesFetch(getInitialMessagesOptions);\n requestCache.set(agentUrlString, promise);\n return promise;\n }\n\n const initialMessages =\n getInitialMessages !== null\n ? use(\n doGetInitialMessages({\n agent: agent.agent,\n name: agent.name,\n url: agentUrlString,\n })\n )\n : rest.initialMessages;\n\n useEffect(() => {\n return () => {\n requestCache.delete(agentUrlString);\n };\n }, [agentUrlString]);\n\n async function aiFetch(\n request: RequestInfo | URL,\n options: RequestInit = {}\n ) {\n // we're going to use a websocket to do the actual \"fetching\"\n // but still satisfy the type signature of the fetch function\n // so we'll return a promise that resolves to a response\n\n const {\n method,\n keepalive,\n headers,\n body,\n redirect,\n integrity,\n signal,\n credentials,\n mode,\n referrer,\n referrerPolicy,\n window,\n // dispatcher, duplex\n } = options;\n const id = crypto.randomUUID();\n const abortController = new AbortController();\n\n signal?.addEventListener(\"abort\", () => {\n abortController.abort();\n });\n\n agent.addEventListener(\n \"message\",\n (event) => {\n let data: OutgoingMessage;\n try {\n data = JSON.parse(event.data) as OutgoingMessage;\n } catch (error) {\n // silently ignore invalid messages for now\n // TODO: log errors with log levels\n return;\n }\n if (data.type === \"cf_agent_use_chat_response\") {\n if (data.id === id) {\n controller.enqueue(new TextEncoder().encode(data.body));\n if (data.done) {\n controller.close();\n abortController.abort();\n }\n }\n }\n },\n { signal: abortController.signal }\n );\n\n let controller: ReadableStreamDefaultController;\n\n const stream = new ReadableStream({\n start(c) {\n controller = c;\n },\n });\n\n agent.send(\n JSON.stringify({\n type: \"cf_agent_use_chat_request\",\n id,\n url: request.toString(),\n init: {\n method,\n keepalive,\n headers,\n body,\n redirect,\n integrity,\n credentials,\n mode,\n referrer,\n referrerPolicy,\n window,\n // dispatcher,\n // duplex\n },\n })\n );\n\n return new Response(stream);\n }\n const useChatHelpers = useChat({\n initialMessages,\n sendExtraMessageFields: true,\n fetch: aiFetch,\n ...rest,\n });\n\n useEffect(() => {\n function onClearHistory(event: MessageEvent) {\n if (typeof event.data !== \"string\") {\n return;\n }\n let data: OutgoingMessage;\n try {\n data = JSON.parse(event.data) as OutgoingMessage;\n } catch (error) {\n // silently ignore invalid messages for now\n // TODO: log errors with log levels\n return;\n }\n if (data.type === \"cf_agent_chat_clear\") {\n useChatHelpers.setMessages([]);\n }\n }\n\n function onMessages(event: MessageEvent) {\n if (typeof event.data !== \"string\") {\n return;\n }\n let data: OutgoingMessage;\n try {\n data = JSON.parse(event.data) as OutgoingMessage;\n } catch (error) {\n // silently ignore invalid messages for now\n // TODO: log errors with log levels\n return;\n }\n if (data.type === \"cf_agent_chat_messages\") {\n useChatHelpers.setMessages(data.messages);\n }\n }\n\n agent.addEventListener(\"message\", onClearHistory);\n agent.addEventListener(\"message\", onMessages);\n\n return () => {\n agent.removeEventListener(\"message\", onClearHistory);\n agent.removeEventListener(\"message\", onMessages);\n };\n }, [agent, useChatHelpers.setMessages]);\n\n return {\n ...useChatHelpers,\n /**\n * Set the chat messages and synchronize with the Agent\n * @param messages New messages to set\n */\n setMessages: (messages: Message[]) => {\n useChatHelpers.setMessages(messages);\n agent.send(\n JSON.stringify({\n type: \"cf_agent_chat_messages\",\n messages,\n })\n );\n },\n /**\n * Clear chat history on both client and Agent\n */\n clearHistory: () => {\n useChatHelpers.setMessages([]);\n agent.send(\n JSON.stringify({\n type: \"cf_agent_chat_clear\",\n })\n );\n },\n };\n}\n"],"mappings":"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","names":["options"]}
@@ -1,6 +1,6 @@
1
1
  import { DurableObject } from 'cloudflare:workers';
2
+ import { Connection, WSMessage } from 'partyserver';
2
3
  import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
3
- import { Connection } from 'partyserver';
4
4
 
5
5
  interface CORSOptions {
6
6
  origin?: string;
@@ -28,9 +28,13 @@ declare abstract class McpAgent<Env = unknown, State = unknown, Props extends Re
28
28
  initRun: boolean;
29
29
  abstract init(): Promise<void>;
30
30
  _init(props: Props): Promise<void>;
31
+ setInitialized(): Promise<void>;
32
+ isInitialized(): Promise<boolean>;
31
33
  fetch(request: Request): Promise<Response>;
32
34
  getWebSocket(): WebSocket | null;
33
- onMCPMessage(sessionId: string, request: Request): Promise<Response>;
35
+ getWebSocketForResponseID(id: string): WebSocket | null;
36
+ onMessage(connection: Connection, event: WSMessage): Promise<void>;
37
+ onSSEMcpMessage(sessionId: string, request: Request): Promise<Error | null>;
34
38
  webSocketMessage(ws: WebSocket, event: ArrayBuffer | string): Promise<void>;
35
39
  webSocketError(ws: WebSocket, error: unknown): Promise<void>;
36
40
  webSocketClose(ws: WebSocket, code: number, reason: string, wasClean: boolean): Promise<void>;
@@ -38,7 +42,19 @@ declare abstract class McpAgent<Env = unknown, State = unknown, Props extends Re
38
42
  binding?: string;
39
43
  corsOptions?: CORSOptions;
40
44
  }): {
41
- fetch: (request: Request, env: Record<string, DurableObjectNamespace<McpAgent>>, ctx: ExecutionContext) => Promise<Response | undefined>;
45
+ fetch: (request: Request, env: Record<string, DurableObjectNamespace<McpAgent>>, ctx: ExecutionContext) => Promise<Response>;
46
+ };
47
+ static serveSSE(path: string, { binding, corsOptions, }?: {
48
+ binding?: string;
49
+ corsOptions?: CORSOptions;
50
+ }): {
51
+ fetch: (request: Request, env: Record<string, DurableObjectNamespace<McpAgent>>, ctx: ExecutionContext) => Promise<Response>;
52
+ };
53
+ static serve(path: string, { binding, corsOptions, }?: {
54
+ binding?: string;
55
+ corsOptions?: CORSOptions;
56
+ }): {
57
+ fetch: (request: Request, env: Record<string, DurableObjectNamespace<McpAgent>>, ctx: ExecutionContext) => Promise<Response>;
42
58
  };
43
59
  }
44
60
 
package/dist/mcp/index.js CHANGED
@@ -10,8 +10,15 @@ import {
10
10
 
11
11
  // src/mcp/index.ts
12
12
  import { DurableObject } from "cloudflare:workers";
13
- import { JSONRPCMessageSchema } from "@modelcontextprotocol/sdk/types.js";
14
- var MAXIMUM_MESSAGE_SIZE = 4 * 1024 * 1024;
13
+ import {
14
+ InitializeRequestSchema,
15
+ isJSONRPCError,
16
+ isJSONRPCNotification,
17
+ isJSONRPCRequest,
18
+ isJSONRPCResponse,
19
+ JSONRPCMessageSchema
20
+ } from "@modelcontextprotocol/sdk/types.js";
21
+ var MAXIMUM_MESSAGE_SIZE_BYTES = 4 * 1024 * 1024;
15
22
  function handleCORS(request, corsOptions) {
16
23
  const origin = request.headers.get("Origin") || "*";
17
24
  const corsHeaders = {
@@ -26,7 +33,7 @@ function handleCORS(request, corsOptions) {
26
33
  return null;
27
34
  }
28
35
  var _getWebSocket, _started;
29
- var McpTransport = class {
36
+ var McpSSETransport = class {
30
37
  constructor(getWebSocket) {
31
38
  __privateAdd(this, _getWebSocket);
32
39
  __privateAdd(this, _started, false);
@@ -59,18 +66,76 @@ var McpTransport = class {
59
66
  };
60
67
  _getWebSocket = new WeakMap();
61
68
  _started = new WeakMap();
62
- var _status, _transport, _connected, _agent, _McpAgent_instances, initialize_fn;
63
- var McpAgent = class extends DurableObject {
69
+ var _getWebSocketForGetRequest, _getWebSocketForMessageID, _notifyResponseIdSent, _started2;
70
+ var McpStreamableHttpTransport = class {
71
+ constructor(getWebSocketForMessageID, notifyResponseIdSent) {
72
+ // TODO: If there is an open connection to send server-initiated messages
73
+ // back, we should use that connection
74
+ __privateAdd(this, _getWebSocketForGetRequest);
75
+ // Get the appropriate websocket connection for a given message id
76
+ __privateAdd(this, _getWebSocketForMessageID);
77
+ // Notify the server that a response has been sent for a given message id
78
+ // so that it may clean up it's mapping of message ids to connections
79
+ // once they are no longer needed
80
+ __privateAdd(this, _notifyResponseIdSent);
81
+ __privateAdd(this, _started2, false);
82
+ __privateSet(this, _getWebSocketForMessageID, getWebSocketForMessageID);
83
+ __privateSet(this, _notifyResponseIdSent, notifyResponseIdSent);
84
+ __privateSet(this, _getWebSocketForGetRequest, () => null);
85
+ }
86
+ async start() {
87
+ if (__privateGet(this, _started2)) {
88
+ throw new Error("Transport already started");
89
+ }
90
+ __privateSet(this, _started2, true);
91
+ }
92
+ async send(message) {
93
+ if (!__privateGet(this, _started2)) {
94
+ throw new Error("Transport not started");
95
+ }
96
+ let websocket = null;
97
+ if (isJSONRPCResponse(message) || isJSONRPCError(message)) {
98
+ websocket = __privateGet(this, _getWebSocketForMessageID).call(this, message.id.toString());
99
+ if (!websocket) {
100
+ throw new Error(
101
+ `Could not find WebSocket for message id: ${message.id}`
102
+ );
103
+ }
104
+ } else if (isJSONRPCRequest(message)) {
105
+ websocket = __privateGet(this, _getWebSocketForGetRequest).call(this);
106
+ } else if (isJSONRPCNotification(message)) {
107
+ websocket = null;
108
+ }
109
+ try {
110
+ websocket?.send(JSON.stringify(message));
111
+ if (isJSONRPCResponse(message)) {
112
+ __privateGet(this, _notifyResponseIdSent).call(this, message.id.toString());
113
+ }
114
+ } catch (error) {
115
+ this.onerror?.(error);
116
+ throw error;
117
+ }
118
+ }
119
+ async close() {
120
+ this.onclose?.();
121
+ }
122
+ };
123
+ _getWebSocketForGetRequest = new WeakMap();
124
+ _getWebSocketForMessageID = new WeakMap();
125
+ _notifyResponseIdSent = new WeakMap();
126
+ _started2 = new WeakMap();
127
+ var _status, _transport, _transportType, _requestIdToConnectionId, _agent, _McpAgent_instances, initialize_fn;
128
+ var _McpAgent = class _McpAgent extends DurableObject {
64
129
  constructor(ctx, env) {
65
130
  var _a;
66
131
  super(ctx, env);
67
132
  __privateAdd(this, _McpAgent_instances);
68
133
  __privateAdd(this, _status, "zero");
69
134
  __privateAdd(this, _transport);
70
- __privateAdd(this, _connected, false);
135
+ __privateAdd(this, _transportType, "unset");
136
+ __privateAdd(this, _requestIdToConnectionId, /* @__PURE__ */ new Map());
71
137
  /**
72
- * Since McpAgent's _aren't_ yet real "Agents" (they route differently, don't support
73
- * websockets, don't support hibernation), let's only expose a couple of the methods
138
+ * Since McpAgent's _aren't_ yet real "Agents", let's only expose a couple of the methods
74
139
  * to the outer class: initialState/state/setState/onStateUpdate/sql
75
140
  */
76
141
  __privateAdd(this, _agent);
@@ -80,6 +145,9 @@ var McpAgent = class extends DurableObject {
80
145
  onStateUpdate(state, source) {
81
146
  return self.onStateUpdate(state, source);
82
147
  }
148
+ async onMessage(connection, message) {
149
+ return self.onMessage(connection, message);
150
+ }
83
151
  }, _a.options = {
84
152
  hibernate: true
85
153
  }, _a)(ctx, env));
@@ -106,22 +174,45 @@ var McpAgent = class extends DurableObject {
106
174
  onStateUpdate(state, source) {
107
175
  return self.onStateUpdate(state, source);
108
176
  }
177
+ async onMessage(connection, event) {
178
+ return self.onMessage(connection, event);
179
+ }
109
180
  }, _a.options = {
110
181
  hibernate: true
111
182
  }, _a)(this.ctx, this.env));
112
183
  this.props = await this.ctx.storage.get("props");
113
- this.init?.();
114
- __privateSet(this, _transport, new McpTransport(() => this.getWebSocket()));
115
- await this.server.connect(__privateGet(this, _transport));
184
+ __privateSet(this, _transportType, await this.ctx.storage.get(
185
+ "transportType"
186
+ ));
187
+ await this._init(this.props);
188
+ if (__privateGet(this, _transportType) === "sse") {
189
+ __privateSet(this, _transport, new McpSSETransport(() => this.getWebSocket()));
190
+ await this.server.connect(__privateGet(this, _transport));
191
+ } else if (__privateGet(this, _transportType) === "streamable-http") {
192
+ __privateSet(this, _transport, new McpStreamableHttpTransport(
193
+ (id) => this.getWebSocketForResponseID(id),
194
+ (id) => __privateGet(this, _requestIdToConnectionId).delete(id)
195
+ ));
196
+ await this.server.connect(__privateGet(this, _transport));
197
+ }
116
198
  }
117
199
  async _init(props) {
118
- await this.ctx.storage.put("props", props);
200
+ await this.ctx.storage.put("props", props ?? {});
201
+ if (!this.ctx.storage.get("transportType")) {
202
+ await this.ctx.storage.put("transportType", "unset");
203
+ }
119
204
  this.props = props;
120
205
  if (!this.initRun) {
121
206
  this.initRun = true;
122
207
  await this.init();
123
208
  }
124
209
  }
210
+ async setInitialized() {
211
+ await this.ctx.storage.put("initialized", true);
212
+ }
213
+ async isInitialized() {
214
+ return await this.ctx.storage.get("initialized") === true;
215
+ }
125
216
  // Allow the worker to fetch a websocket connection to the agent
126
217
  async fetch(request) {
127
218
  if (__privateGet(this, _status) !== "started") {
@@ -133,18 +224,41 @@ var McpAgent = class extends DurableObject {
133
224
  });
134
225
  }
135
226
  const url = new URL(request.url);
136
- const sessionId = url.searchParams.get("sessionId");
137
- if (!sessionId) {
138
- return new Response("Missing sessionId", { status: 400 });
139
- }
140
- if (__privateGet(this, _connected)) {
141
- return new Response("WebSocket already connected", { status: 400 });
227
+ const path = url.pathname;
228
+ switch (path) {
229
+ case "/sse": {
230
+ const websockets = this.ctx.getWebSockets();
231
+ if (websockets.length > 0) {
232
+ return new Response("Websocket already connected", { status: 400 });
233
+ }
234
+ await this.ctx.storage.put("transportType", "sse");
235
+ __privateSet(this, _transportType, "sse");
236
+ if (!__privateGet(this, _transport)) {
237
+ __privateSet(this, _transport, new McpSSETransport(() => this.getWebSocket()));
238
+ await this.server.connect(__privateGet(this, _transport));
239
+ }
240
+ return __privateGet(this, _agent).fetch(request);
241
+ }
242
+ case "/streamable-http": {
243
+ if (!__privateGet(this, _transport)) {
244
+ __privateSet(this, _transport, new McpStreamableHttpTransport(
245
+ (id) => this.getWebSocketForResponseID(id),
246
+ (id) => __privateGet(this, _requestIdToConnectionId).delete(id)
247
+ ));
248
+ await this.server.connect(__privateGet(this, _transport));
249
+ }
250
+ await this.ctx.storage.put("transportType", "streamable-http");
251
+ __privateSet(this, _transportType, "streamable-http");
252
+ return __privateGet(this, _agent).fetch(request);
253
+ }
254
+ default:
255
+ return new Response(
256
+ "Internal Server Error: Expected /sse or /streamable-http path",
257
+ {
258
+ status: 500
259
+ }
260
+ );
142
261
  }
143
- const response = await __privateGet(this, _agent).fetch(request);
144
- __privateSet(this, _connected, true);
145
- __privateSet(this, _transport, new McpTransport(() => this.getWebSocket()));
146
- await this.server.connect(__privateGet(this, _transport));
147
- return response;
148
262
  }
149
263
  getWebSocket() {
150
264
  const websockets = this.ctx.getWebSockets();
@@ -153,26 +267,45 @@ var McpAgent = class extends DurableObject {
153
267
  }
154
268
  return websockets[0];
155
269
  }
156
- async onMCPMessage(sessionId, request) {
270
+ getWebSocketForResponseID(id) {
271
+ const connectionId = __privateGet(this, _requestIdToConnectionId).get(id);
272
+ if (connectionId === void 0) {
273
+ return null;
274
+ }
275
+ return __privateGet(this, _agent).getConnection(connectionId) ?? null;
276
+ }
277
+ // All messages received here. This is currently never called
278
+ async onMessage(connection, event) {
279
+ if (__privateGet(this, _transportType) !== "streamable-http") {
280
+ const err = new Error(
281
+ "Internal Server Error: Expected streamable-http protocol"
282
+ );
283
+ __privateGet(this, _transport)?.onerror?.(err);
284
+ return;
285
+ }
286
+ let message;
287
+ try {
288
+ const data = typeof event === "string" ? event : new TextDecoder().decode(event);
289
+ message = JSONRPCMessageSchema.parse(JSON.parse(data));
290
+ } catch (error) {
291
+ __privateGet(this, _transport)?.onerror?.(error);
292
+ return;
293
+ }
294
+ if (isJSONRPCRequest(message)) {
295
+ __privateGet(this, _requestIdToConnectionId).set(message.id.toString(), connection.id);
296
+ }
297
+ __privateGet(this, _transport)?.onmessage?.(message);
298
+ }
299
+ // All messages received over SSE after the initial connection has been established
300
+ // will be passed here
301
+ async onSSEMcpMessage(sessionId, request) {
157
302
  if (__privateGet(this, _status) !== "started") {
158
303
  await __privateMethod(this, _McpAgent_instances, initialize_fn).call(this);
159
304
  }
305
+ if (__privateGet(this, _transportType) !== "sse") {
306
+ return new Error("Internal Server Error: Expected SSE protocol");
307
+ }
160
308
  try {
161
- const contentType = request.headers.get("content-type") || "";
162
- if (!contentType.includes("application/json")) {
163
- return new Response(`Unsupported content-type: ${contentType}`, {
164
- status: 400
165
- });
166
- }
167
- const contentLength = Number.parseInt(
168
- request.headers.get("content-length") || "0",
169
- 10
170
- );
171
- if (contentLength > MAXIMUM_MESSAGE_SIZE) {
172
- return new Response(`Request body too large: ${contentLength} bytes`, {
173
- status: 400
174
- });
175
- }
176
309
  const message = await request.json();
177
310
  let parsedMessage;
178
311
  try {
@@ -182,44 +315,41 @@ var McpAgent = class extends DurableObject {
182
315
  throw error;
183
316
  }
184
317
  __privateGet(this, _transport)?.onmessage?.(parsedMessage);
185
- return new Response("Accepted", { status: 202 });
318
+ return null;
186
319
  } catch (error) {
187
320
  __privateGet(this, _transport)?.onerror?.(error);
188
- return new Response(String(error), { status: 400 });
321
+ return error;
189
322
  }
190
323
  }
191
- // This is unused since there are no incoming websocket messages
324
+ // Delegate all websocket events to the underlying agent
192
325
  async webSocketMessage(ws, event) {
193
- let message;
194
- try {
195
- const data = typeof event === "string" ? event : new TextDecoder().decode(event);
196
- message = JSONRPCMessageSchema.parse(JSON.parse(data));
197
- } catch (error) {
198
- __privateGet(this, _transport)?.onerror?.(error);
199
- return;
200
- }
201
326
  if (__privateGet(this, _status) !== "started") {
202
327
  await __privateMethod(this, _McpAgent_instances, initialize_fn).call(this);
203
328
  }
204
- __privateGet(this, _transport)?.onmessage?.(message);
329
+ return await __privateGet(this, _agent).webSocketMessage(ws, event);
205
330
  }
206
331
  // WebSocket event handlers for hibernation support
207
332
  async webSocketError(ws, error) {
208
333
  if (__privateGet(this, _status) !== "started") {
209
334
  await __privateMethod(this, _McpAgent_instances, initialize_fn).call(this);
210
335
  }
211
- __privateGet(this, _transport)?.onerror?.(error);
336
+ return await __privateGet(this, _agent).webSocketError(ws, error);
212
337
  }
213
338
  async webSocketClose(ws, code, reason, wasClean) {
214
339
  if (__privateGet(this, _status) !== "started") {
215
340
  await __privateMethod(this, _McpAgent_instances, initialize_fn).call(this);
216
341
  }
217
- __privateGet(this, _transport)?.onclose?.();
218
- __privateSet(this, _connected, false);
342
+ return await __privateGet(this, _agent).webSocketClose(ws, code, reason, wasClean);
219
343
  }
220
344
  static mount(path, {
221
345
  binding = "MCP_OBJECT",
222
346
  corsOptions
347
+ } = {}) {
348
+ return _McpAgent.serveSSE(path, { binding, corsOptions });
349
+ }
350
+ static serveSSE(path, {
351
+ binding = "MCP_OBJECT",
352
+ corsOptions
223
353
  } = {}) {
224
354
  let pathname = path;
225
355
  if (path === "/") {
@@ -243,11 +373,11 @@ data: ${encodeURI(`${pathname}/message`)}?sessionId=${sessionId}
243
373
 
244
374
  `;
245
375
  writer.write(encoder.encode(endpointMessage));
246
- const id = namespace.idFromString(sessionId);
376
+ const id = namespace.idFromName(`sse:${sessionId}`);
247
377
  const doStub = namespace.get(id);
248
378
  await doStub._init(ctx.props);
249
379
  const upgradeUrl = new URL(request.url);
250
- upgradeUrl.searchParams.set("sessionId", sessionId);
380
+ upgradeUrl.pathname = "/sse";
251
381
  const response = await doStub.fetch(
252
382
  new Request(upgradeUrl, {
253
383
  headers: {
@@ -261,37 +391,48 @@ data: ${encodeURI(`${pathname}/message`)}?sessionId=${sessionId}
261
391
  if (!ws) {
262
392
  console.error("Failed to establish WebSocket connection");
263
393
  await writer.close();
264
- return;
394
+ return new Response("Failed to establish WebSocket connection", {
395
+ status: 500
396
+ });
265
397
  }
266
398
  ws.accept();
267
- ws.addEventListener("message", async (event) => {
268
- try {
269
- const message = JSON.parse(event.data);
270
- const result = JSONRPCMessageSchema.safeParse(message);
271
- if (!result.success) {
272
- return;
273
- }
274
- const messageText = `event: message
399
+ ws.addEventListener("message", (event) => {
400
+ async function onMessage(event2) {
401
+ try {
402
+ const message = JSON.parse(event2.data);
403
+ const result = JSONRPCMessageSchema.safeParse(message);
404
+ if (!result.success) {
405
+ return;
406
+ }
407
+ const messageText = `event: message
275
408
  data: ${JSON.stringify(result.data)}
276
409
 
277
410
  `;
278
- await writer.write(encoder.encode(messageText));
279
- } catch (error) {
280
- console.error("Error forwarding message to SSE:", error);
411
+ await writer.write(encoder.encode(messageText));
412
+ } catch (error) {
413
+ console.error("Error forwarding message to SSE:", error);
414
+ }
281
415
  }
416
+ onMessage(event).catch(console.error);
282
417
  });
283
- ws.addEventListener("error", async (error) => {
284
- try {
285
- await writer.close();
286
- } catch (e) {
418
+ ws.addEventListener("error", (error) => {
419
+ async function onError(error2) {
420
+ try {
421
+ await writer.close();
422
+ } catch (e) {
423
+ }
287
424
  }
425
+ onError(error).catch(console.error);
288
426
  });
289
- ws.addEventListener("close", async () => {
290
- try {
291
- await writer.close();
292
- } catch (error) {
293
- console.error("Error closing SSE connection:", error);
427
+ ws.addEventListener("close", () => {
428
+ async function onClose() {
429
+ try {
430
+ await writer.close();
431
+ } catch (error) {
432
+ console.error("Error closing SSE connection:", error);
433
+ }
294
434
  }
435
+ onClose().catch(console.error);
295
436
  });
296
437
  return new Response(readable, {
297
438
  headers: {
@@ -310,30 +451,317 @@ data: ${JSON.stringify(result.data)}
310
451
  { status: 400 }
311
452
  );
312
453
  }
313
- const object = namespace.get(namespace.idFromString(sessionId));
314
- const response = await object.onMCPMessage(sessionId, request);
315
- const headers = new Headers();
316
- response.headers.forEach?.((value, key) => {
317
- headers.set(key, value);
318
- });
319
- headers.set(
320
- "Access-Control-Allow-Origin",
321
- corsOptions?.origin || "*"
454
+ const contentType = request.headers.get("content-type") || "";
455
+ if (!contentType.includes("application/json")) {
456
+ return new Response(`Unsupported content-type: ${contentType}`, {
457
+ status: 400
458
+ });
459
+ }
460
+ const contentLength = Number.parseInt(
461
+ request.headers.get("content-length") || "0",
462
+ 10
322
463
  );
323
- return new Response(response.body, {
324
- status: response.status,
325
- statusText: response.statusText,
326
- headers
464
+ if (contentLength > MAXIMUM_MESSAGE_SIZE_BYTES) {
465
+ return new Response(
466
+ `Request body too large: ${contentLength} bytes`,
467
+ {
468
+ status: 400
469
+ }
470
+ );
471
+ }
472
+ const id = namespace.idFromName(`sse:${sessionId}`);
473
+ const doStub = namespace.get(id);
474
+ const error = await doStub.onSSEMcpMessage(sessionId, request);
475
+ if (error) {
476
+ return new Response(error.message, {
477
+ status: 400,
478
+ headers: {
479
+ "Content-Type": "text/event-stream",
480
+ "Cache-Control": "no-cache",
481
+ Connection: "keep-alive",
482
+ "Access-Control-Allow-Origin": corsOptions?.origin || "*"
483
+ }
484
+ });
485
+ }
486
+ return new Response("Accepted", {
487
+ status: 202,
488
+ headers: {
489
+ "Content-Type": "text/event-stream",
490
+ "Cache-Control": "no-cache",
491
+ Connection: "keep-alive",
492
+ "Access-Control-Allow-Origin": corsOptions?.origin || "*"
493
+ }
327
494
  });
328
495
  }
329
496
  return new Response("Not Found", { status: 404 });
330
497
  }
331
498
  };
332
499
  }
500
+ static serve(path, {
501
+ binding = "MCP_OBJECT",
502
+ corsOptions
503
+ } = {}) {
504
+ let pathname = path;
505
+ if (path === "/") {
506
+ pathname = "/*";
507
+ }
508
+ const basePattern = new URLPattern({ pathname });
509
+ return {
510
+ fetch: async (request, env, ctx) => {
511
+ const corsResponse = handleCORS(request, corsOptions);
512
+ if (corsResponse) {
513
+ return corsResponse;
514
+ }
515
+ const url = new URL(request.url);
516
+ const namespace = env[binding];
517
+ if (request.method === "POST" && basePattern.test(url)) {
518
+ const acceptHeader = request.headers.get("accept");
519
+ if (!acceptHeader?.includes("application/json") || !acceptHeader.includes("text/event-stream")) {
520
+ const body2 = JSON.stringify({
521
+ jsonrpc: "2.0",
522
+ error: {
523
+ code: -32e3,
524
+ message: "Not Acceptable: Client must accept both application/json and text/event-stream"
525
+ },
526
+ id: null
527
+ });
528
+ return new Response(body2, { status: 406 });
529
+ }
530
+ const ct = request.headers.get("content-type");
531
+ if (!ct || !ct.includes("application/json")) {
532
+ const body2 = JSON.stringify({
533
+ jsonrpc: "2.0",
534
+ error: {
535
+ code: -32e3,
536
+ message: "Unsupported Media Type: Content-Type must be application/json"
537
+ },
538
+ id: null
539
+ });
540
+ return new Response(body2, { status: 415 });
541
+ }
542
+ const contentLength = Number.parseInt(
543
+ request.headers.get("content-length") ?? "0",
544
+ 10
545
+ );
546
+ if (contentLength > MAXIMUM_MESSAGE_SIZE_BYTES) {
547
+ const body2 = JSON.stringify({
548
+ jsonrpc: "2.0",
549
+ error: {
550
+ code: -32e3,
551
+ message: `Request body too large. Maximum size is ${MAXIMUM_MESSAGE_SIZE_BYTES} bytes`
552
+ },
553
+ id: null
554
+ });
555
+ return new Response(body2, { status: 413 });
556
+ }
557
+ let sessionId = request.headers.get("mcp-session-id");
558
+ let rawMessage;
559
+ try {
560
+ rawMessage = await request.json();
561
+ } catch (error) {
562
+ const body2 = JSON.stringify({
563
+ jsonrpc: "2.0",
564
+ error: {
565
+ code: -32700,
566
+ message: "Parse error: Invalid JSON"
567
+ },
568
+ id: null
569
+ });
570
+ return new Response(body2, { status: 400 });
571
+ }
572
+ let arrayMessage;
573
+ if (Array.isArray(rawMessage)) {
574
+ arrayMessage = rawMessage;
575
+ } else {
576
+ arrayMessage = [rawMessage];
577
+ }
578
+ let messages = [];
579
+ for (const msg of arrayMessage) {
580
+ if (!JSONRPCMessageSchema.safeParse(msg).success) {
581
+ const body2 = JSON.stringify({
582
+ jsonrpc: "2.0",
583
+ error: {
584
+ code: -32700,
585
+ message: "Parse error: Invalid JSON-RPC message"
586
+ },
587
+ id: null
588
+ });
589
+ return new Response(body2, { status: 400 });
590
+ }
591
+ }
592
+ messages = arrayMessage.map((msg) => JSONRPCMessageSchema.parse(msg));
593
+ const isInitializationRequest = messages.some(
594
+ (msg) => InitializeRequestSchema.safeParse(msg).success
595
+ );
596
+ if (isInitializationRequest && sessionId) {
597
+ const body2 = JSON.stringify({
598
+ jsonrpc: "2.0",
599
+ error: {
600
+ code: -32600,
601
+ message: "Invalid Request: Initialization requests must not include a sessionId"
602
+ },
603
+ id: null
604
+ });
605
+ return new Response(body2, { status: 400 });
606
+ }
607
+ if (isInitializationRequest && messages.length > 1) {
608
+ const body2 = JSON.stringify({
609
+ jsonrpc: "2.0",
610
+ error: {
611
+ code: -32600,
612
+ message: "Invalid Request: Only one initialization request is allowed"
613
+ },
614
+ id: null
615
+ });
616
+ return new Response(body2, { status: 400 });
617
+ }
618
+ if (!isInitializationRequest && !sessionId) {
619
+ const body2 = JSON.stringify({
620
+ jsonrpc: "2.0",
621
+ error: {
622
+ code: -32e3,
623
+ message: "Bad Request: Mcp-Session-Id header is required"
624
+ },
625
+ id: null
626
+ });
627
+ return new Response(body2, { status: 400 });
628
+ }
629
+ sessionId = sessionId ?? namespace.newUniqueId().toString();
630
+ const id = namespace.idFromName(`streamable-http:${sessionId}`);
631
+ const doStub = namespace.get(id);
632
+ const isInitialized = await doStub.isInitialized();
633
+ if (isInitializationRequest) {
634
+ await doStub.setInitialized();
635
+ } else if (!isInitialized) {
636
+ const body2 = JSON.stringify({
637
+ jsonrpc: "2.0",
638
+ error: {
639
+ code: -32001,
640
+ message: "Session not found"
641
+ },
642
+ id: null
643
+ });
644
+ return new Response(body2, { status: 404 });
645
+ }
646
+ const { readable, writable } = new TransformStream();
647
+ const writer = writable.getWriter();
648
+ const encoder = new TextEncoder();
649
+ const upgradeUrl = new URL(request.url);
650
+ upgradeUrl.pathname = "/streamable-http";
651
+ const response = await doStub.fetch(
652
+ new Request(upgradeUrl, {
653
+ headers: {
654
+ Upgrade: "websocket",
655
+ // Required by PartyServer
656
+ "x-partykit-room": sessionId
657
+ }
658
+ })
659
+ );
660
+ const ws = response.webSocket;
661
+ if (!ws) {
662
+ console.error("Failed to establish WebSocket connection");
663
+ await writer.close();
664
+ const body2 = JSON.stringify({
665
+ jsonrpc: "2.0",
666
+ error: {
667
+ code: -32001,
668
+ message: "Failed to establish WebSocket connection"
669
+ },
670
+ id: null
671
+ });
672
+ return new Response(body2, { status: 500 });
673
+ }
674
+ const requestIds = /* @__PURE__ */ new Set();
675
+ ws.accept();
676
+ ws.addEventListener("message", (event) => {
677
+ async function onMessage(event2) {
678
+ try {
679
+ const data = typeof event2.data === "string" ? event2.data : new TextDecoder().decode(event2.data);
680
+ const message = JSON.parse(data);
681
+ const result = JSONRPCMessageSchema.safeParse(message);
682
+ if (!result.success) {
683
+ return;
684
+ }
685
+ if (isJSONRPCResponse(result.data) || isJSONRPCError(result.data)) {
686
+ requestIds.delete(result.data.id);
687
+ }
688
+ const messageText = `event: message
689
+ data: ${JSON.stringify(result.data)}
690
+
691
+ `;
692
+ await writer.write(encoder.encode(messageText));
693
+ if (requestIds.size === 0) {
694
+ ws.close();
695
+ }
696
+ } catch (error) {
697
+ console.error("Error forwarding message to SSE:", error);
698
+ }
699
+ }
700
+ onMessage(event).catch(console.error);
701
+ });
702
+ ws.addEventListener("error", (error) => {
703
+ async function onError(error2) {
704
+ try {
705
+ await writer.close();
706
+ } catch (e) {
707
+ }
708
+ }
709
+ onError(error).catch(console.error);
710
+ });
711
+ ws.addEventListener("close", () => {
712
+ async function onClose() {
713
+ try {
714
+ await writer.close();
715
+ } catch (error) {
716
+ console.error("Error closing SSE connection:", error);
717
+ }
718
+ }
719
+ onClose().catch(console.error);
720
+ });
721
+ const hasOnlyNotificationsOrResponses = messages.every(
722
+ (msg) => isJSONRPCNotification(msg) || isJSONRPCResponse(msg)
723
+ );
724
+ if (hasOnlyNotificationsOrResponses) {
725
+ for (const message of messages) {
726
+ ws.send(JSON.stringify(message));
727
+ }
728
+ ws.close();
729
+ return new Response(null, { status: 202 });
730
+ }
731
+ for (const message of messages) {
732
+ if (isJSONRPCRequest(message)) {
733
+ requestIds.add(message.id);
734
+ }
735
+ ws.send(JSON.stringify(message));
736
+ }
737
+ return new Response(readable, {
738
+ headers: {
739
+ "Content-Type": "text/event-stream",
740
+ "Cache-Control": "no-cache",
741
+ Connection: "keep-alive",
742
+ "mcp-session-id": sessionId,
743
+ "Access-Control-Allow-Origin": corsOptions?.origin || "*"
744
+ },
745
+ status: 200
746
+ });
747
+ }
748
+ const body = JSON.stringify({
749
+ jsonrpc: "2.0",
750
+ error: {
751
+ code: -32e3,
752
+ message: "Method not allowed"
753
+ },
754
+ id: null
755
+ });
756
+ return new Response(body, { status: 405 });
757
+ }
758
+ };
759
+ }
333
760
  };
334
761
  _status = new WeakMap();
335
762
  _transport = new WeakMap();
336
- _connected = new WeakMap();
763
+ _transportType = new WeakMap();
764
+ _requestIdToConnectionId = new WeakMap();
337
765
  _agent = new WeakMap();
338
766
  _McpAgent_instances = new WeakSet();
339
767
  initialize_fn = async function() {
@@ -343,6 +771,7 @@ initialize_fn = async function() {
343
771
  __privateSet(this, _status, "started");
344
772
  });
345
773
  };
774
+ var McpAgent = _McpAgent;
346
775
  export {
347
776
  McpAgent
348
777
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/mcp/index.ts"],"sourcesContent":["import { DurableObject } from \"cloudflare:workers\";\nimport { Agent } from \"../\";\nimport type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport type { Connection } from \"../\";\nimport type { JSONRPCMessage } from \"@modelcontextprotocol/sdk/types.js\";\nimport { JSONRPCMessageSchema } from \"@modelcontextprotocol/sdk/types.js\";\nimport type { Transport } from \"@modelcontextprotocol/sdk/shared/transport.js\";\n\nconst MAXIMUM_MESSAGE_SIZE = 4 * 1024 * 1024; // 4MB\n\n// CORS helper function\nfunction handleCORS(\n request: Request,\n corsOptions?: CORSOptions\n): Response | null {\n const origin = request.headers.get(\"Origin\") || \"*\";\n const corsHeaders = {\n \"Access-Control-Allow-Origin\": corsOptions?.origin || origin,\n \"Access-Control-Allow-Methods\":\n corsOptions?.methods || \"GET, POST, OPTIONS\",\n \"Access-Control-Allow-Headers\": corsOptions?.headers || \"Content-Type\",\n \"Access-Control-Max-Age\": (corsOptions?.maxAge || 86400).toString(),\n };\n\n if (request.method === \"OPTIONS\") {\n return new Response(null, { headers: corsHeaders });\n }\n\n return null;\n}\n\ninterface CORSOptions {\n origin?: string;\n methods?: string;\n headers?: string;\n maxAge?: number;\n}\n\nclass McpTransport implements Transport {\n onclose?: () => void;\n onerror?: (error: Error) => void;\n onmessage?: (message: JSONRPCMessage) => void;\n sessionId?: string;\n\n #getWebSocket: () => WebSocket | null;\n #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\nexport abstract class McpAgent<\n Env = unknown,\n State = unknown,\n Props extends Record<string, unknown> = Record<string, unknown>,\n> extends DurableObject<Env> {\n #status: \"zero\" | \"starting\" | \"started\" = \"zero\";\n #transport?: McpTransport;\n #connected = false;\n\n /**\n * Since McpAgent's _aren't_ yet real \"Agents\" (they route differently, don't support\n * websockets, don't support hibernation), let's only expose a couple of the methods\n * to the outer class: initialState/state/setState/onStateUpdate/sql\n */\n #agent: Agent<Env, State>;\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 })(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 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 })(this.ctx, this.env);\n\n this.props = (await this.ctx.storage.get(\"props\")) as Props;\n this.init?.();\n\n // Connect to the MCP server\n this.#transport = new McpTransport(() => this.getWebSocket());\n await this.server.connect(this.#transport);\n }\n\n /**\n * McpAgent API\n */\n abstract server: McpServer;\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 this.props = props;\n if (!this.initRun) {\n this.initRun = true;\n await this.init();\n }\n }\n\n 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 const url = new URL(request.url);\n const sessionId = url.searchParams.get(\"sessionId\");\n if (!sessionId) {\n return new Response(\"Missing sessionId\", { status: 400 });\n }\n\n // For now, each agent can only have one connection\n // If we get an upgrade while already connected, we should error\n if (this.#connected) {\n return new Response(\"WebSocket already connected\", { status: 400 });\n }\n\n // Defer to the Agent's fetch method to handle the WebSocket connection\n // PartyServer does a lot to manage the connections under the hood\n const response = await this.#agent.fetch(request);\n\n this.#connected = true;\n\n // Connect to the MCP server\n this.#transport = new McpTransport(() => this.getWebSocket());\n await this.server.connect(this.#transport);\n\n return response;\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 async onMCPMessage(sessionId: string, 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 try {\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) {\n return new Response(`Request body too large: ${contentLength} bytes`, {\n status: 400,\n });\n }\n\n // Clone the request before reading the body to avoid stream issues\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 new Response(\"Accepted\", { status: 202 });\n } catch (error) {\n this.#transport?.onerror?.(error as Error);\n return new Response(String(error), { status: 400 });\n }\n }\n\n // This is unused since there are no incoming websocket messages\n async webSocketMessage(ws: WebSocket, event: ArrayBuffer | string) {\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 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 this.#transport?.onmessage?.(message);\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 this.#transport?.onerror?.(error as 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 this.#transport?.onclose?.();\n this.#connected = false;\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 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 fetch: async (\n request: Request,\n env: Record<string, DurableObjectNamespace<McpAgent>>,\n ctx: ExecutionContext\n ) => {\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 namespace = env[binding];\n\n // Handle SSE connections\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 endpointMessage = `event: endpoint\\ndata: ${encodeURI(`${pathname}/message`)}?sessionId=${sessionId}\\n\\n`;\n writer.write(encoder.encode(endpointMessage));\n\n // Get the Durable Object\n const id = namespace.idFromString(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 upgradeUrl.searchParams.set(\"sessionId\", sessionId);\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;\n }\n\n // Accept the WebSocket\n ws.accept();\n\n // Handle messages from the Durable Object\n ws.addEventListener(\"message\", async (event) => {\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\n // Handle WebSocket errors\n ws.addEventListener(\"error\", async (error) => {\n try {\n await writer.close();\n } catch (e) {\n // Ignore errors when closing\n }\n });\n\n // Handle WebSocket closure\n ws.addEventListener(\"close\", async () => {\n try {\n await writer.close();\n } catch (error) {\n console.error(\"Error closing SSE connection:\", error);\n }\n });\n\n // Return the SSE response\n return new Response(readable, {\n headers: {\n \"Content-Type\": \"text/event-stream\",\n \"Cache-Control\": \"no-cache\",\n Connection: \"keep-alive\",\n \"Access-Control-Allow-Origin\": corsOptions?.origin || \"*\",\n },\n });\n }\n\n // Handle MCP messages\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 // Get the Durable Object\n const object = namespace.get(namespace.idFromString(sessionId));\n\n // Forward the request to the Durable Object\n const response = await object.onMCPMessage(sessionId, request);\n\n // Add CORS headers\n const headers = new Headers();\n response.headers.forEach?.((value, key) => {\n headers.set(key, value);\n });\n headers.set(\n \"Access-Control-Allow-Origin\",\n corsOptions?.origin || \"*\"\n );\n\n return new Response(response.body as unknown as BodyInit, {\n status: response.status,\n statusText: response.statusText,\n headers,\n });\n }\n\n return new Response(\"Not Found\", { status: 404 });\n },\n };\n }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/mcp/index.ts"],"sourcesContent":["import { DurableObject } from \"cloudflare:workers\";\nimport { Agent } from \"../\";\nimport type { WSMessage } from \"../\";\nimport type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport type { Connection } from \"../\";\nimport type {\n JSONRPCError,\n JSONRPCMessage,\n JSONRPCNotification,\n JSONRPCRequest,\n JSONRPCResponse,\n} from \"@modelcontextprotocol/sdk/types.js\";\nimport type { Transport } from \"@modelcontextprotocol/sdk/shared/transport.js\";\nimport {\n InitializeRequestSchema,\n isJSONRPCError,\n isJSONRPCNotification,\n isJSONRPCRequest,\n isJSONRPCResponse,\n JSONRPCErrorSchema,\n JSONRPCMessageSchema,\n JSONRPCNotificationSchema,\n JSONRPCRequestSchema,\n JSONRPCResponseSchema,\n} from \"@modelcontextprotocol/sdk/types.js\";\n\nconst MAXIMUM_MESSAGE_SIZE_BYTES = 4 * 1024 * 1024; // 4MB\n\n// CORS helper function\nfunction handleCORS(\n request: Request,\n corsOptions?: CORSOptions\n): Response | null {\n const origin = request.headers.get(\"Origin\") || \"*\";\n const corsHeaders = {\n \"Access-Control-Allow-Origin\": corsOptions?.origin || origin,\n \"Access-Control-Allow-Methods\":\n corsOptions?.methods || \"GET, POST, OPTIONS\",\n \"Access-Control-Allow-Headers\": corsOptions?.headers || \"Content-Type\",\n \"Access-Control-Max-Age\": (corsOptions?.maxAge || 86400).toString(),\n };\n\n if (request.method === \"OPTIONS\") {\n return new Response(null, { headers: corsHeaders });\n }\n\n return null;\n}\n\ninterface CORSOptions {\n origin?: string;\n methods?: string;\n headers?: string;\n maxAge?: number;\n}\n\nclass McpSSETransport implements Transport {\n onclose?: () => void;\n onerror?: (error: Error) => void;\n onmessage?: (message: JSONRPCMessage) => void;\n sessionId?: string;\n\n #getWebSocket: () => WebSocket | null;\n #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 #getWebSocketForGetRequest: () => WebSocket | null;\n\n // Get the appropriate websocket connection for a given message id\n #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 #notifyResponseIdSent: (id: string) => void;\n\n #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\nexport abstract class McpAgent<\n Env = unknown,\n State = unknown,\n Props extends Record<string, unknown> = Record<string, unknown>,\n> extends DurableObject<Env> {\n #status: \"zero\" | \"starting\" | \"started\" = \"zero\";\n #transport?: Transport;\n #transportType: TransportType = \"unset\";\n #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 #agent: Agent<Env, State>;\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 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 // Connect to the MCP server\n if (this.#transportType === \"sse\") {\n this.#transport = new McpSSETransport(() => this.getWebSocket());\n await this.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 this.server.connect(this.#transport);\n }\n }\n\n /**\n * McpAgent API\n */\n abstract server: McpServer;\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 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\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 this.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 this.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 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 fetch: async (\n request: Request,\n env: Record<string, DurableObjectNamespace<McpAgent>>,\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 namespace = env[binding];\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 endpointMessage = `event: endpoint\\ndata: ${encodeURI(`${pathname}/message`)}?sessionId=${sessionId}\\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 \"Content-Type\": \"text/event-stream\",\n \"Cache-Control\": \"no-cache\",\n Connection: \"keep-alive\",\n \"Access-Control-Allow-Origin\": corsOptions?.origin || \"*\",\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 status: 400,\n headers: {\n \"Content-Type\": \"text/event-stream\",\n \"Cache-Control\": \"no-cache\",\n Connection: \"keep-alive\",\n \"Access-Control-Allow-Origin\": corsOptions?.origin || \"*\",\n },\n });\n }\n\n return new Response(\"Accepted\", {\n status: 202,\n headers: {\n \"Content-Type\": \"text/event-stream\",\n \"Cache-Control\": \"no-cache\",\n Connection: \"keep-alive\",\n \"Access-Control-Allow-Origin\": corsOptions?.origin || \"*\",\n },\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 fetch: async (\n request: Request,\n env: Record<string, DurableObjectNamespace<McpAgent>>,\n ctx: ExecutionContext\n ) => {\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 namespace = env[binding];\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 jsonrpc: \"2.0\",\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 });\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 jsonrpc: \"2.0\",\n error: {\n code: -32000,\n message:\n \"Unsupported Media Type: Content-Type must be application/json\",\n },\n id: null,\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 jsonrpc: \"2.0\",\n error: {\n code: -32000,\n message: `Request body too large. Maximum size is ${MAXIMUM_MESSAGE_SIZE_BYTES} bytes`,\n },\n id: null,\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 jsonrpc: \"2.0\",\n error: {\n code: -32700,\n message: \"Parse error: Invalid JSON\",\n },\n id: null,\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 jsonrpc: \"2.0\",\n error: {\n code: -32700,\n message: \"Parse error: Invalid JSON-RPC message\",\n },\n id: null,\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 jsonrpc: \"2.0\",\n error: {\n code: -32600,\n message:\n \"Invalid Request: Initialization requests must not include a sessionId\",\n },\n id: null,\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 jsonrpc: \"2.0\",\n error: {\n code: -32600,\n message:\n \"Invalid Request: Only one initialization request is allowed\",\n },\n id: null,\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 jsonrpc: \"2.0\",\n error: {\n code: -32000,\n message: \"Bad Request: Mcp-Session-Id header is required\",\n },\n id: null,\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.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 jsonrpc: \"2.0\",\n error: {\n code: -32001,\n message: \"Session not found\",\n },\n id: null,\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 jsonrpc: \"2.0\",\n error: {\n code: -32001,\n message: \"Failed to establish WebSocket connection\",\n },\n id: null,\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, { status: 202 });\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 \"Content-Type\": \"text/event-stream\",\n \"Cache-Control\": \"no-cache\",\n Connection: \"keep-alive\",\n \"mcp-session-id\": sessionId,\n \"Access-Control-Allow-Origin\": corsOptions?.origin || \"*\",\n },\n status: 200,\n });\n }\n\n // We don't yet support GET or DELETE requests\n const body = JSON.stringify({\n jsonrpc: \"2.0\",\n error: {\n code: -32000,\n message: \"Method not allowed\",\n },\n id: null,\n });\n return new Response(body, { status: 405 });\n },\n };\n }\n}\n"],"mappings":"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","names":["_started","event","error","body"]}
package/package.json CHANGED
@@ -1,10 +1,11 @@
1
1
  {
2
2
  "name": "agents",
3
- "version": "0.0.61",
3
+ "version": "0.0.63",
4
4
  "main": "src/index.ts",
5
5
  "type": "module",
6
6
  "scripts": {
7
- "test": "echo \"Error: no test specified\" && exit 1",
7
+ "check:test": "vitest -r src/tests --watch false",
8
+ "test": "vitest -r src/tests",
8
9
  "evals": "(cd evals; evalite)",
9
10
  "build": "tsx ./scripts/build.ts"
10
11
  },
@@ -77,10 +78,18 @@
77
78
  "license": "MIT",
78
79
  "description": "A home for your AI agents",
79
80
  "dependencies": {
80
- "@modelcontextprotocol/sdk": "^1.9.0",
81
+ "@modelcontextprotocol/sdk": "^1.10.2",
82
+ "ai": "^4.3.9",
81
83
  "cron-schedule": "^5.0.4",
82
84
  "nanoid": "^5.1.5",
83
- "partyserver": "^0.0.66",
84
- "partysocket": "1.1.3"
85
+ "partyserver": "^0.0.67",
86
+ "partysocket": "1.1.3",
87
+ "zod": "^3.24.3"
88
+ },
89
+ "peerDependencies": {
90
+ "react": "*"
91
+ },
92
+ "devDependencies": {
93
+ "react": "*"
85
94
  }
86
95
  }