agents 0.0.0-956c772 → 0.0.0-9688c15

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/mcp/index.js CHANGED
@@ -1,6 +1,9 @@
1
1
  import {
2
2
  Agent
3
- } from "../chunk-YMUU7QHV.js";
3
+ } from "../chunk-YFPCCSZO.js";
4
+ import "../chunk-D6UOOELW.js";
5
+ import "../chunk-RN4SNE73.js";
6
+ import "../chunk-25YDMV4H.js";
4
7
  import {
5
8
  __privateAdd,
6
9
  __privateGet,
@@ -10,23 +13,33 @@ import {
10
13
 
11
14
  // src/mcp/index.ts
12
15
  import { DurableObject } from "cloudflare:workers";
13
- import { JSONRPCMessageSchema } from "@modelcontextprotocol/sdk/types.js";
14
- var MAXIMUM_MESSAGE_SIZE = 4 * 1024 * 1024;
15
- function handleCORS(request, corsOptions) {
16
- const origin = request.headers.get("Origin") || "*";
17
- const corsHeaders = {
18
- "Access-Control-Allow-Origin": corsOptions?.origin || origin,
19
- "Access-Control-Allow-Methods": corsOptions?.methods || "GET, POST, OPTIONS",
20
- "Access-Control-Allow-Headers": corsOptions?.headers || "Content-Type",
21
- "Access-Control-Max-Age": (corsOptions?.maxAge || 86400).toString()
16
+ import {
17
+ InitializeRequestSchema,
18
+ isJSONRPCError,
19
+ isJSONRPCNotification,
20
+ isJSONRPCRequest,
21
+ isJSONRPCResponse,
22
+ JSONRPCMessageSchema
23
+ } from "@modelcontextprotocol/sdk/types.js";
24
+ var MAXIMUM_MESSAGE_SIZE_BYTES = 4 * 1024 * 1024;
25
+ function corsHeaders(request, corsOptions = {}) {
26
+ const origin = "*";
27
+ return {
28
+ "Access-Control-Allow-Origin": corsOptions.origin || origin,
29
+ "Access-Control-Allow-Methods": corsOptions.methods || "GET, POST, OPTIONS",
30
+ "Access-Control-Allow-Headers": corsOptions.headers || "Content-Type, mcp-session-id",
31
+ "Access-Control-Max-Age": (corsOptions.maxAge || 86400).toString(),
32
+ "Access-Control-Expose-Headers": corsOptions.exposeHeaders || "mcp-session-id"
22
33
  };
34
+ }
35
+ function handleCORS(request, corsOptions) {
23
36
  if (request.method === "OPTIONS") {
24
- return new Response(null, { headers: corsHeaders });
37
+ return new Response(null, { headers: corsHeaders(request, corsOptions) });
25
38
  }
26
39
  return null;
27
40
  }
28
41
  var _getWebSocket, _started;
29
- var McpTransport = class {
42
+ var McpSSETransport = class {
30
43
  constructor(getWebSocket) {
31
44
  __privateAdd(this, _getWebSocket);
32
45
  __privateAdd(this, _started, false);
@@ -59,18 +72,76 @@ var McpTransport = class {
59
72
  };
60
73
  _getWebSocket = new WeakMap();
61
74
  _started = new WeakMap();
62
- var _status, _transport, _connected, _agent, _McpAgent_instances, initialize_fn;
63
- var McpAgent = class extends DurableObject {
75
+ var _getWebSocketForGetRequest, _getWebSocketForMessageID, _notifyResponseIdSent, _started2;
76
+ var McpStreamableHttpTransport = class {
77
+ constructor(getWebSocketForMessageID, notifyResponseIdSent) {
78
+ // TODO: If there is an open connection to send server-initiated messages
79
+ // back, we should use that connection
80
+ __privateAdd(this, _getWebSocketForGetRequest);
81
+ // Get the appropriate websocket connection for a given message id
82
+ __privateAdd(this, _getWebSocketForMessageID);
83
+ // Notify the server that a response has been sent for a given message id
84
+ // so that it may clean up it's mapping of message ids to connections
85
+ // once they are no longer needed
86
+ __privateAdd(this, _notifyResponseIdSent);
87
+ __privateAdd(this, _started2, false);
88
+ __privateSet(this, _getWebSocketForMessageID, getWebSocketForMessageID);
89
+ __privateSet(this, _notifyResponseIdSent, notifyResponseIdSent);
90
+ __privateSet(this, _getWebSocketForGetRequest, () => null);
91
+ }
92
+ async start() {
93
+ if (__privateGet(this, _started2)) {
94
+ throw new Error("Transport already started");
95
+ }
96
+ __privateSet(this, _started2, true);
97
+ }
98
+ async send(message) {
99
+ if (!__privateGet(this, _started2)) {
100
+ throw new Error("Transport not started");
101
+ }
102
+ let websocket = null;
103
+ if (isJSONRPCResponse(message) || isJSONRPCError(message)) {
104
+ websocket = __privateGet(this, _getWebSocketForMessageID).call(this, message.id.toString());
105
+ if (!websocket) {
106
+ throw new Error(
107
+ `Could not find WebSocket for message id: ${message.id}`
108
+ );
109
+ }
110
+ } else if (isJSONRPCRequest(message)) {
111
+ websocket = __privateGet(this, _getWebSocketForGetRequest).call(this);
112
+ } else if (isJSONRPCNotification(message)) {
113
+ websocket = null;
114
+ }
115
+ try {
116
+ websocket?.send(JSON.stringify(message));
117
+ if (isJSONRPCResponse(message)) {
118
+ __privateGet(this, _notifyResponseIdSent).call(this, message.id.toString());
119
+ }
120
+ } catch (error) {
121
+ this.onerror?.(error);
122
+ throw error;
123
+ }
124
+ }
125
+ async close() {
126
+ this.onclose?.();
127
+ }
128
+ };
129
+ _getWebSocketForGetRequest = new WeakMap();
130
+ _getWebSocketForMessageID = new WeakMap();
131
+ _notifyResponseIdSent = new WeakMap();
132
+ _started2 = new WeakMap();
133
+ var _status, _transport, _transportType, _requestIdToConnectionId, _agent, _McpAgent_instances, initialize_fn;
134
+ var _McpAgent = class _McpAgent extends DurableObject {
64
135
  constructor(ctx, env) {
65
136
  var _a;
66
137
  super(ctx, env);
67
138
  __privateAdd(this, _McpAgent_instances);
68
139
  __privateAdd(this, _status, "zero");
69
140
  __privateAdd(this, _transport);
70
- __privateAdd(this, _connected, false);
141
+ __privateAdd(this, _transportType, "unset");
142
+ __privateAdd(this, _requestIdToConnectionId, /* @__PURE__ */ new Map());
71
143
  /**
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
144
+ * Since McpAgent's _aren't_ yet real "Agents", let's only expose a couple of the methods
74
145
  * to the outer class: initialState/state/setState/onStateUpdate/sql
75
146
  */
76
147
  __privateAdd(this, _agent);
@@ -80,10 +151,16 @@ var McpAgent = class extends DurableObject {
80
151
  onStateUpdate(state, source) {
81
152
  return self.onStateUpdate(state, source);
82
153
  }
154
+ async onMessage(connection, message) {
155
+ return self.onMessage(connection, message);
156
+ }
83
157
  }, _a.options = {
84
158
  hibernate: true
85
159
  }, _a)(ctx, env));
86
160
  }
161
+ get mcp() {
162
+ return __privateGet(this, _agent).mcp;
163
+ }
87
164
  get state() {
88
165
  return __privateGet(this, _agent).state;
89
166
  }
@@ -106,22 +183,46 @@ var McpAgent = class extends DurableObject {
106
183
  onStateUpdate(state, source) {
107
184
  return self.onStateUpdate(state, source);
108
185
  }
186
+ async onMessage(connection, event) {
187
+ return self.onMessage(connection, event);
188
+ }
109
189
  }, _a.options = {
110
190
  hibernate: true
111
191
  }, _a)(this.ctx, this.env));
112
192
  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));
193
+ __privateSet(this, _transportType, await this.ctx.storage.get(
194
+ "transportType"
195
+ ));
196
+ await this._init(this.props);
197
+ const server = await this.server;
198
+ if (__privateGet(this, _transportType) === "sse") {
199
+ __privateSet(this, _transport, new McpSSETransport(() => this.getWebSocket()));
200
+ await server.connect(__privateGet(this, _transport));
201
+ } else if (__privateGet(this, _transportType) === "streamable-http") {
202
+ __privateSet(this, _transport, new McpStreamableHttpTransport(
203
+ (id) => this.getWebSocketForResponseID(id),
204
+ (id) => __privateGet(this, _requestIdToConnectionId).delete(id)
205
+ ));
206
+ await server.connect(__privateGet(this, _transport));
207
+ }
116
208
  }
117
209
  async _init(props) {
118
- await this.ctx.storage.put("props", props);
210
+ await this.ctx.storage.put("props", props ?? {});
211
+ if (!this.ctx.storage.get("transportType")) {
212
+ await this.ctx.storage.put("transportType", "unset");
213
+ }
119
214
  this.props = props;
120
215
  if (!this.initRun) {
121
216
  this.initRun = true;
122
217
  await this.init();
123
218
  }
124
219
  }
220
+ async setInitialized() {
221
+ await this.ctx.storage.put("initialized", true);
222
+ }
223
+ async isInitialized() {
224
+ return await this.ctx.storage.get("initialized") === true;
225
+ }
125
226
  // Allow the worker to fetch a websocket connection to the agent
126
227
  async fetch(request) {
127
228
  if (__privateGet(this, _status) !== "started") {
@@ -133,18 +234,42 @@ var McpAgent = class extends DurableObject {
133
234
  });
134
235
  }
135
236
  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 });
237
+ const path = url.pathname;
238
+ const server = await this.server;
239
+ switch (path) {
240
+ case "/sse": {
241
+ const websockets = this.ctx.getWebSockets();
242
+ if (websockets.length > 0) {
243
+ return new Response("Websocket already connected", { status: 400 });
244
+ }
245
+ await this.ctx.storage.put("transportType", "sse");
246
+ __privateSet(this, _transportType, "sse");
247
+ if (!__privateGet(this, _transport)) {
248
+ __privateSet(this, _transport, new McpSSETransport(() => this.getWebSocket()));
249
+ await server.connect(__privateGet(this, _transport));
250
+ }
251
+ return __privateGet(this, _agent).fetch(request);
252
+ }
253
+ case "/streamable-http": {
254
+ if (!__privateGet(this, _transport)) {
255
+ __privateSet(this, _transport, new McpStreamableHttpTransport(
256
+ (id) => this.getWebSocketForResponseID(id),
257
+ (id) => __privateGet(this, _requestIdToConnectionId).delete(id)
258
+ ));
259
+ await server.connect(__privateGet(this, _transport));
260
+ }
261
+ await this.ctx.storage.put("transportType", "streamable-http");
262
+ __privateSet(this, _transportType, "streamable-http");
263
+ return __privateGet(this, _agent).fetch(request);
264
+ }
265
+ default:
266
+ return new Response(
267
+ "Internal Server Error: Expected /sse or /streamable-http path",
268
+ {
269
+ status: 500
270
+ }
271
+ );
142
272
  }
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
273
  }
149
274
  getWebSocket() {
150
275
  const websockets = this.ctx.getWebSockets();
@@ -153,26 +278,45 @@ var McpAgent = class extends DurableObject {
153
278
  }
154
279
  return websockets[0];
155
280
  }
156
- async onMCPMessage(sessionId, request) {
281
+ getWebSocketForResponseID(id) {
282
+ const connectionId = __privateGet(this, _requestIdToConnectionId).get(id);
283
+ if (connectionId === void 0) {
284
+ return null;
285
+ }
286
+ return __privateGet(this, _agent).getConnection(connectionId) ?? null;
287
+ }
288
+ // All messages received here. This is currently never called
289
+ async onMessage(connection, event) {
290
+ if (__privateGet(this, _transportType) !== "streamable-http") {
291
+ const err = new Error(
292
+ "Internal Server Error: Expected streamable-http protocol"
293
+ );
294
+ __privateGet(this, _transport)?.onerror?.(err);
295
+ return;
296
+ }
297
+ let message;
298
+ try {
299
+ const data = typeof event === "string" ? event : new TextDecoder().decode(event);
300
+ message = JSONRPCMessageSchema.parse(JSON.parse(data));
301
+ } catch (error) {
302
+ __privateGet(this, _transport)?.onerror?.(error);
303
+ return;
304
+ }
305
+ if (isJSONRPCRequest(message)) {
306
+ __privateGet(this, _requestIdToConnectionId).set(message.id.toString(), connection.id);
307
+ }
308
+ __privateGet(this, _transport)?.onmessage?.(message);
309
+ }
310
+ // All messages received over SSE after the initial connection has been established
311
+ // will be passed here
312
+ async onSSEMcpMessage(sessionId, request) {
157
313
  if (__privateGet(this, _status) !== "started") {
158
314
  await __privateMethod(this, _McpAgent_instances, initialize_fn).call(this);
159
315
  }
316
+ if (__privateGet(this, _transportType) !== "sse") {
317
+ return new Error("Internal Server Error: Expected SSE protocol");
318
+ }
160
319
  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
320
  const message = await request.json();
177
321
  let parsedMessage;
178
322
  try {
@@ -182,44 +326,42 @@ var McpAgent = class extends DurableObject {
182
326
  throw error;
183
327
  }
184
328
  __privateGet(this, _transport)?.onmessage?.(parsedMessage);
185
- return new Response("Accepted", { status: 202 });
329
+ return null;
186
330
  } catch (error) {
331
+ console.error("Error forwarding message to SSE:", error);
187
332
  __privateGet(this, _transport)?.onerror?.(error);
188
- return new Response(String(error), { status: 400 });
333
+ return error;
189
334
  }
190
335
  }
191
- // This is unused since there are no incoming websocket messages
336
+ // Delegate all websocket events to the underlying agent
192
337
  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
338
  if (__privateGet(this, _status) !== "started") {
202
339
  await __privateMethod(this, _McpAgent_instances, initialize_fn).call(this);
203
340
  }
204
- __privateGet(this, _transport)?.onmessage?.(message);
341
+ return await __privateGet(this, _agent).webSocketMessage(ws, event);
205
342
  }
206
343
  // WebSocket event handlers for hibernation support
207
344
  async webSocketError(ws, error) {
208
345
  if (__privateGet(this, _status) !== "started") {
209
346
  await __privateMethod(this, _McpAgent_instances, initialize_fn).call(this);
210
347
  }
211
- __privateGet(this, _transport)?.onerror?.(error);
348
+ return await __privateGet(this, _agent).webSocketError(ws, error);
212
349
  }
213
350
  async webSocketClose(ws, code, reason, wasClean) {
214
351
  if (__privateGet(this, _status) !== "started") {
215
352
  await __privateMethod(this, _McpAgent_instances, initialize_fn).call(this);
216
353
  }
217
- __privateGet(this, _transport)?.onclose?.();
218
- __privateSet(this, _connected, false);
354
+ return await __privateGet(this, _agent).webSocketClose(ws, code, reason, wasClean);
219
355
  }
220
356
  static mount(path, {
221
357
  binding = "MCP_OBJECT",
222
358
  corsOptions
359
+ } = {}) {
360
+ return _McpAgent.serveSSE(path, { binding, corsOptions });
361
+ }
362
+ static serveSSE(path, {
363
+ binding = "MCP_OBJECT",
364
+ corsOptions
223
365
  } = {}) {
224
366
  let pathname = path;
225
367
  if (path === "/") {
@@ -228,26 +370,40 @@ var McpAgent = class extends DurableObject {
228
370
  const basePattern = new URLPattern({ pathname });
229
371
  const messagePattern = new URLPattern({ pathname: `${pathname}/message` });
230
372
  return {
231
- fetch: async (request, env, ctx) => {
373
+ async fetch(request, env, ctx) {
232
374
  const corsResponse = handleCORS(request, corsOptions);
233
375
  if (corsResponse) return corsResponse;
234
376
  const url = new URL(request.url);
235
- const namespace = env[binding];
377
+ const bindingValue = env[binding];
378
+ if (bindingValue == null || typeof bindingValue !== "object") {
379
+ console.error(
380
+ `Could not find McpAgent binding for ${binding}. Did you update your wrangler configuration?`
381
+ );
382
+ return new Response("Invalid binding", { status: 500 });
383
+ }
384
+ if (bindingValue.toString() !== "[object DurableObjectNamespace]") {
385
+ return new Response("Invalid binding", { status: 500 });
386
+ }
387
+ const namespace = bindingValue;
236
388
  if (request.method === "GET" && basePattern.test(url)) {
237
389
  const sessionId = url.searchParams.get("sessionId") || namespace.newUniqueId().toString();
238
390
  const { readable, writable } = new TransformStream();
239
391
  const writer = writable.getWriter();
240
392
  const encoder = new TextEncoder();
393
+ const endpointUrl = new URL(request.url);
394
+ endpointUrl.pathname = encodeURI(`${pathname}/message`);
395
+ endpointUrl.searchParams.set("sessionId", sessionId);
396
+ const relativeUrlWithSession = endpointUrl.pathname + endpointUrl.search + endpointUrl.hash;
241
397
  const endpointMessage = `event: endpoint
242
- data: ${encodeURI(`${pathname}/message`)}?sessionId=${sessionId}
398
+ data: ${relativeUrlWithSession}
243
399
 
244
400
  `;
245
401
  writer.write(encoder.encode(endpointMessage));
246
- const id = namespace.idFromString(sessionId);
402
+ const id = namespace.idFromName(`sse:${sessionId}`);
247
403
  const doStub = namespace.get(id);
248
404
  await doStub._init(ctx.props);
249
405
  const upgradeUrl = new URL(request.url);
250
- upgradeUrl.searchParams.set("sessionId", sessionId);
406
+ upgradeUrl.pathname = "/sse";
251
407
  const response = await doStub.fetch(
252
408
  new Request(upgradeUrl, {
253
409
  headers: {
@@ -261,44 +417,55 @@ data: ${encodeURI(`${pathname}/message`)}?sessionId=${sessionId}
261
417
  if (!ws) {
262
418
  console.error("Failed to establish WebSocket connection");
263
419
  await writer.close();
264
- return;
420
+ return new Response("Failed to establish WebSocket connection", {
421
+ status: 500
422
+ });
265
423
  }
266
424
  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
425
+ ws.addEventListener("message", (event) => {
426
+ async function onMessage(event2) {
427
+ try {
428
+ const message = JSON.parse(event2.data);
429
+ const result = JSONRPCMessageSchema.safeParse(message);
430
+ if (!result.success) {
431
+ return;
432
+ }
433
+ const messageText = `event: message
275
434
  data: ${JSON.stringify(result.data)}
276
435
 
277
436
  `;
278
- await writer.write(encoder.encode(messageText));
279
- } catch (error) {
280
- console.error("Error forwarding message to SSE:", error);
437
+ await writer.write(encoder.encode(messageText));
438
+ } catch (error) {
439
+ console.error("Error forwarding message to SSE:", error);
440
+ }
281
441
  }
442
+ onMessage(event).catch(console.error);
282
443
  });
283
- ws.addEventListener("error", async (error) => {
284
- try {
285
- await writer.close();
286
- } catch (e) {
444
+ ws.addEventListener("error", (error) => {
445
+ async function onError(error2) {
446
+ try {
447
+ await writer.close();
448
+ } catch (e) {
449
+ }
287
450
  }
451
+ onError(error).catch(console.error);
288
452
  });
289
- ws.addEventListener("close", async () => {
290
- try {
291
- await writer.close();
292
- } catch (error) {
293
- console.error("Error closing SSE connection:", error);
453
+ ws.addEventListener("close", () => {
454
+ async function onClose() {
455
+ try {
456
+ await writer.close();
457
+ } catch (error) {
458
+ console.error("Error closing SSE connection:", error);
459
+ }
294
460
  }
461
+ onClose().catch(console.error);
295
462
  });
296
463
  return new Response(readable, {
297
464
  headers: {
298
465
  "Content-Type": "text/event-stream",
299
466
  "Cache-Control": "no-cache",
300
467
  Connection: "keep-alive",
301
- "Access-Control-Allow-Origin": corsOptions?.origin || "*"
468
+ ...corsHeaders(request, corsOptions)
302
469
  }
303
470
  });
304
471
  }
@@ -310,30 +477,331 @@ data: ${JSON.stringify(result.data)}
310
477
  { status: 400 }
311
478
  );
312
479
  }
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 || "*"
480
+ const contentType = request.headers.get("content-type") || "";
481
+ if (!contentType.includes("application/json")) {
482
+ return new Response(`Unsupported content-type: ${contentType}`, {
483
+ status: 400
484
+ });
485
+ }
486
+ const contentLength = Number.parseInt(
487
+ request.headers.get("content-length") || "0",
488
+ 10
322
489
  );
323
- return new Response(response.body, {
324
- status: response.status,
325
- statusText: response.statusText,
326
- headers
490
+ if (contentLength > MAXIMUM_MESSAGE_SIZE_BYTES) {
491
+ return new Response(
492
+ `Request body too large: ${contentLength} bytes`,
493
+ {
494
+ status: 400
495
+ }
496
+ );
497
+ }
498
+ const id = namespace.idFromName(`sse:${sessionId}`);
499
+ const doStub = namespace.get(id);
500
+ const error = await doStub.onSSEMcpMessage(sessionId, request);
501
+ if (error) {
502
+ return new Response(error.message, {
503
+ status: 400,
504
+ headers: {
505
+ "Content-Type": "text/event-stream",
506
+ "Cache-Control": "no-cache",
507
+ Connection: "keep-alive",
508
+ ...corsHeaders(request, corsOptions)
509
+ }
510
+ });
511
+ }
512
+ return new Response("Accepted", {
513
+ status: 202,
514
+ headers: {
515
+ "Content-Type": "text/event-stream",
516
+ "Cache-Control": "no-cache",
517
+ Connection: "keep-alive",
518
+ ...corsHeaders(request, corsOptions)
519
+ }
327
520
  });
328
521
  }
329
522
  return new Response("Not Found", { status: 404 });
330
523
  }
331
524
  };
332
525
  }
526
+ static serve(path, {
527
+ binding = "MCP_OBJECT",
528
+ corsOptions
529
+ } = {}) {
530
+ let pathname = path;
531
+ if (path === "/") {
532
+ pathname = "/*";
533
+ }
534
+ const basePattern = new URLPattern({ pathname });
535
+ return {
536
+ async fetch(request, env, ctx) {
537
+ const corsResponse = handleCORS(request, corsOptions);
538
+ if (corsResponse) {
539
+ return corsResponse;
540
+ }
541
+ const url = new URL(request.url);
542
+ const bindingValue = env[binding];
543
+ if (bindingValue == null || typeof bindingValue !== "object") {
544
+ console.error(
545
+ `Could not find McpAgent binding for ${binding}. Did you update your wrangler configuration?`
546
+ );
547
+ return new Response("Invalid binding", { status: 500 });
548
+ }
549
+ if (bindingValue.toString() !== "[object DurableObjectNamespace]") {
550
+ return new Response("Invalid binding", { status: 500 });
551
+ }
552
+ const namespace = bindingValue;
553
+ if (request.method === "POST" && basePattern.test(url)) {
554
+ const acceptHeader = request.headers.get("accept");
555
+ if (!acceptHeader?.includes("application/json") || !acceptHeader.includes("text/event-stream")) {
556
+ const body2 = JSON.stringify({
557
+ jsonrpc: "2.0",
558
+ error: {
559
+ code: -32e3,
560
+ message: "Not Acceptable: Client must accept both application/json and text/event-stream"
561
+ },
562
+ id: null
563
+ });
564
+ return new Response(body2, { status: 406 });
565
+ }
566
+ const ct = request.headers.get("content-type");
567
+ if (!ct || !ct.includes("application/json")) {
568
+ const body2 = JSON.stringify({
569
+ jsonrpc: "2.0",
570
+ error: {
571
+ code: -32e3,
572
+ message: "Unsupported Media Type: Content-Type must be application/json"
573
+ },
574
+ id: null
575
+ });
576
+ return new Response(body2, { status: 415 });
577
+ }
578
+ const contentLength = Number.parseInt(
579
+ request.headers.get("content-length") ?? "0",
580
+ 10
581
+ );
582
+ if (contentLength > MAXIMUM_MESSAGE_SIZE_BYTES) {
583
+ const body2 = JSON.stringify({
584
+ jsonrpc: "2.0",
585
+ error: {
586
+ code: -32e3,
587
+ message: `Request body too large. Maximum size is ${MAXIMUM_MESSAGE_SIZE_BYTES} bytes`
588
+ },
589
+ id: null
590
+ });
591
+ return new Response(body2, { status: 413 });
592
+ }
593
+ let sessionId = request.headers.get("mcp-session-id");
594
+ let rawMessage;
595
+ try {
596
+ rawMessage = await request.json();
597
+ } catch (error) {
598
+ const body2 = JSON.stringify({
599
+ jsonrpc: "2.0",
600
+ error: {
601
+ code: -32700,
602
+ message: "Parse error: Invalid JSON"
603
+ },
604
+ id: null
605
+ });
606
+ return new Response(body2, { status: 400 });
607
+ }
608
+ let arrayMessage;
609
+ if (Array.isArray(rawMessage)) {
610
+ arrayMessage = rawMessage;
611
+ } else {
612
+ arrayMessage = [rawMessage];
613
+ }
614
+ let messages = [];
615
+ for (const msg of arrayMessage) {
616
+ if (!JSONRPCMessageSchema.safeParse(msg).success) {
617
+ const body2 = JSON.stringify({
618
+ jsonrpc: "2.0",
619
+ error: {
620
+ code: -32700,
621
+ message: "Parse error: Invalid JSON-RPC message"
622
+ },
623
+ id: null
624
+ });
625
+ return new Response(body2, { status: 400 });
626
+ }
627
+ }
628
+ messages = arrayMessage.map((msg) => JSONRPCMessageSchema.parse(msg));
629
+ const isInitializationRequest = messages.some(
630
+ (msg) => InitializeRequestSchema.safeParse(msg).success
631
+ );
632
+ if (isInitializationRequest && sessionId) {
633
+ const body2 = JSON.stringify({
634
+ jsonrpc: "2.0",
635
+ error: {
636
+ code: -32600,
637
+ message: "Invalid Request: Initialization requests must not include a sessionId"
638
+ },
639
+ id: null
640
+ });
641
+ return new Response(body2, { status: 400 });
642
+ }
643
+ if (isInitializationRequest && messages.length > 1) {
644
+ const body2 = JSON.stringify({
645
+ jsonrpc: "2.0",
646
+ error: {
647
+ code: -32600,
648
+ message: "Invalid Request: Only one initialization request is allowed"
649
+ },
650
+ id: null
651
+ });
652
+ return new Response(body2, { status: 400 });
653
+ }
654
+ if (!isInitializationRequest && !sessionId) {
655
+ const body2 = JSON.stringify({
656
+ jsonrpc: "2.0",
657
+ error: {
658
+ code: -32e3,
659
+ message: "Bad Request: Mcp-Session-Id header is required"
660
+ },
661
+ id: null
662
+ });
663
+ return new Response(body2, { status: 400 });
664
+ }
665
+ sessionId = sessionId ?? namespace.newUniqueId().toString();
666
+ const id = namespace.idFromName(`streamable-http:${sessionId}`);
667
+ const doStub = namespace.get(id);
668
+ const isInitialized = await doStub.isInitialized();
669
+ if (isInitializationRequest) {
670
+ await doStub._init(ctx.props);
671
+ await doStub.setInitialized();
672
+ } else if (!isInitialized) {
673
+ const body2 = JSON.stringify({
674
+ jsonrpc: "2.0",
675
+ error: {
676
+ code: -32001,
677
+ message: "Session not found"
678
+ },
679
+ id: null
680
+ });
681
+ return new Response(body2, { status: 404 });
682
+ }
683
+ const { readable, writable } = new TransformStream();
684
+ const writer = writable.getWriter();
685
+ const encoder = new TextEncoder();
686
+ const upgradeUrl = new URL(request.url);
687
+ upgradeUrl.pathname = "/streamable-http";
688
+ const response = await doStub.fetch(
689
+ new Request(upgradeUrl, {
690
+ headers: {
691
+ Upgrade: "websocket",
692
+ // Required by PartyServer
693
+ "x-partykit-room": sessionId
694
+ }
695
+ })
696
+ );
697
+ const ws = response.webSocket;
698
+ if (!ws) {
699
+ console.error("Failed to establish WebSocket connection");
700
+ await writer.close();
701
+ const body2 = JSON.stringify({
702
+ jsonrpc: "2.0",
703
+ error: {
704
+ code: -32001,
705
+ message: "Failed to establish WebSocket connection"
706
+ },
707
+ id: null
708
+ });
709
+ return new Response(body2, { status: 500 });
710
+ }
711
+ const requestIds = /* @__PURE__ */ new Set();
712
+ ws.accept();
713
+ ws.addEventListener("message", (event) => {
714
+ async function onMessage(event2) {
715
+ try {
716
+ const data = typeof event2.data === "string" ? event2.data : new TextDecoder().decode(event2.data);
717
+ const message = JSON.parse(data);
718
+ const result = JSONRPCMessageSchema.safeParse(message);
719
+ if (!result.success) {
720
+ return;
721
+ }
722
+ if (isJSONRPCResponse(result.data) || isJSONRPCError(result.data)) {
723
+ requestIds.delete(result.data.id);
724
+ }
725
+ const messageText = `event: message
726
+ data: ${JSON.stringify(result.data)}
727
+
728
+ `;
729
+ await writer.write(encoder.encode(messageText));
730
+ if (requestIds.size === 0) {
731
+ ws.close();
732
+ }
733
+ } catch (error) {
734
+ console.error("Error forwarding message to SSE:", error);
735
+ }
736
+ }
737
+ onMessage(event).catch(console.error);
738
+ });
739
+ ws.addEventListener("error", (error) => {
740
+ async function onError(error2) {
741
+ try {
742
+ await writer.close();
743
+ } catch (e) {
744
+ }
745
+ }
746
+ onError(error).catch(console.error);
747
+ });
748
+ ws.addEventListener("close", () => {
749
+ async function onClose() {
750
+ try {
751
+ await writer.close();
752
+ } catch (error) {
753
+ console.error("Error closing SSE connection:", error);
754
+ }
755
+ }
756
+ onClose().catch(console.error);
757
+ });
758
+ const hasOnlyNotificationsOrResponses = messages.every(
759
+ (msg) => isJSONRPCNotification(msg) || isJSONRPCResponse(msg)
760
+ );
761
+ if (hasOnlyNotificationsOrResponses) {
762
+ for (const message of messages) {
763
+ ws.send(JSON.stringify(message));
764
+ }
765
+ ws.close();
766
+ return new Response(null, {
767
+ status: 202,
768
+ headers: corsHeaders(request, corsOptions)
769
+ });
770
+ }
771
+ for (const message of messages) {
772
+ if (isJSONRPCRequest(message)) {
773
+ requestIds.add(message.id);
774
+ }
775
+ ws.send(JSON.stringify(message));
776
+ }
777
+ return new Response(readable, {
778
+ headers: {
779
+ "Content-Type": "text/event-stream",
780
+ "Cache-Control": "no-cache",
781
+ Connection: "keep-alive",
782
+ "mcp-session-id": sessionId,
783
+ ...corsHeaders(request, corsOptions)
784
+ },
785
+ status: 200
786
+ });
787
+ }
788
+ const body = JSON.stringify({
789
+ jsonrpc: "2.0",
790
+ error: {
791
+ code: -32e3,
792
+ message: "Method not allowed"
793
+ },
794
+ id: null
795
+ });
796
+ return new Response(body, { status: 405 });
797
+ }
798
+ };
799
+ }
333
800
  };
334
801
  _status = new WeakMap();
335
802
  _transport = new WeakMap();
336
- _connected = new WeakMap();
803
+ _transportType = new WeakMap();
804
+ _requestIdToConnectionId = new WeakMap();
337
805
  _agent = new WeakMap();
338
806
  _McpAgent_instances = new WeakSet();
339
807
  initialize_fn = async function() {
@@ -343,6 +811,7 @@ initialize_fn = async function() {
343
811
  __privateSet(this, _status, "started");
344
812
  });
345
813
  };
814
+ var McpAgent = _McpAgent;
346
815
  export {
347
816
  McpAgent
348
817
  };