agents 0.0.0-956c772 → 0.0.0-96a8138

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