agents 0.0.0-86dfe61 → 0.0.0-881f11e

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