agents 0.0.0-b8377c1 → 0.0.0-ba99b7c

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-WNIGPPNB.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,41 @@ 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) {
187
326
  __privateGet(this, _transport)?.onerror?.(error);
188
- return new Response(String(error), { status: 400 });
327
+ return error;
189
328
  }
190
329
  }
191
- // This is unused since there are no incoming websocket messages
330
+ // Delegate all websocket events to the underlying agent
192
331
  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
332
  if (__privateGet(this, _status) !== "started") {
202
333
  await __privateMethod(this, _McpAgent_instances, initialize_fn).call(this);
203
334
  }
204
- __privateGet(this, _transport)?.onmessage?.(message);
335
+ return await __privateGet(this, _agent).webSocketMessage(ws, event);
205
336
  }
206
337
  // WebSocket event handlers for hibernation support
207
338
  async webSocketError(ws, error) {
208
339
  if (__privateGet(this, _status) !== "started") {
209
340
  await __privateMethod(this, _McpAgent_instances, initialize_fn).call(this);
210
341
  }
211
- __privateGet(this, _transport)?.onerror?.(error);
342
+ return await __privateGet(this, _agent).webSocketError(ws, error);
212
343
  }
213
344
  async webSocketClose(ws, code, reason, wasClean) {
214
345
  if (__privateGet(this, _status) !== "started") {
215
346
  await __privateMethod(this, _McpAgent_instances, initialize_fn).call(this);
216
347
  }
217
- __privateGet(this, _transport)?.onclose?.();
218
- __privateSet(this, _connected, false);
348
+ return await __privateGet(this, _agent).webSocketClose(ws, code, reason, wasClean);
219
349
  }
220
350
  static mount(path, {
221
351
  binding = "MCP_OBJECT",
222
352
  corsOptions
353
+ } = {}) {
354
+ return _McpAgent.serveSSE(path, { binding, corsOptions });
355
+ }
356
+ static serveSSE(path, {
357
+ binding = "MCP_OBJECT",
358
+ corsOptions
223
359
  } = {}) {
224
360
  let pathname = path;
225
361
  if (path === "/") {
@@ -228,26 +364,40 @@ var McpAgent = class extends DurableObject {
228
364
  const basePattern = new URLPattern({ pathname });
229
365
  const messagePattern = new URLPattern({ pathname: `${pathname}/message` });
230
366
  return {
231
- fetch: async (request, env, ctx) => {
367
+ async fetch(request, env, ctx) {
232
368
  const corsResponse = handleCORS(request, corsOptions);
233
369
  if (corsResponse) return corsResponse;
234
370
  const url = new URL(request.url);
235
- const namespace = env[binding];
371
+ const bindingValue = env[binding];
372
+ if (bindingValue == null || typeof bindingValue !== "object") {
373
+ console.error(
374
+ `Could not find McpAgent binding for ${binding}. Did you update your wrangler configuration?`
375
+ );
376
+ return new Response("Invalid binding", { status: 500 });
377
+ }
378
+ if (bindingValue.toString() !== "[object DurableObjectNamespace]") {
379
+ return new Response("Invalid binding", { status: 500 });
380
+ }
381
+ const namespace = bindingValue;
236
382
  if (request.method === "GET" && basePattern.test(url)) {
237
383
  const sessionId = url.searchParams.get("sessionId") || namespace.newUniqueId().toString();
238
384
  const { readable, writable } = new TransformStream();
239
385
  const writer = writable.getWriter();
240
386
  const encoder = new TextEncoder();
387
+ const endpointUrl = new URL(request.url);
388
+ endpointUrl.pathname = encodeURI(`${pathname}/message`);
389
+ endpointUrl.searchParams.set("sessionId", sessionId);
390
+ const relativeUrlWithSession = endpointUrl.pathname + endpointUrl.search + endpointUrl.hash;
241
391
  const endpointMessage = `event: endpoint
242
- data: ${encodeURI(`${pathname}/message`)}?sessionId=${sessionId}
392
+ data: ${relativeUrlWithSession}
243
393
 
244
394
  `;
245
395
  writer.write(encoder.encode(endpointMessage));
246
- const id = namespace.idFromString(sessionId);
396
+ const id = namespace.idFromName(`sse:${sessionId}`);
247
397
  const doStub = namespace.get(id);
248
398
  await doStub._init(ctx.props);
249
399
  const upgradeUrl = new URL(request.url);
250
- upgradeUrl.searchParams.set("sessionId", sessionId);
400
+ upgradeUrl.pathname = "/sse";
251
401
  const response = await doStub.fetch(
252
402
  new Request(upgradeUrl, {
253
403
  headers: {
@@ -261,37 +411,48 @@ data: ${encodeURI(`${pathname}/message`)}?sessionId=${sessionId}
261
411
  if (!ws) {
262
412
  console.error("Failed to establish WebSocket connection");
263
413
  await writer.close();
264
- return;
414
+ return new Response("Failed to establish WebSocket connection", {
415
+ status: 500
416
+ });
265
417
  }
266
418
  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
419
+ ws.addEventListener("message", (event) => {
420
+ async function onMessage(event2) {
421
+ try {
422
+ const message = JSON.parse(event2.data);
423
+ const result = JSONRPCMessageSchema.safeParse(message);
424
+ if (!result.success) {
425
+ return;
426
+ }
427
+ const messageText = `event: message
275
428
  data: ${JSON.stringify(result.data)}
276
429
 
277
430
  `;
278
- await writer.write(encoder.encode(messageText));
279
- } catch (error) {
280
- console.error("Error forwarding message to SSE:", error);
431
+ await writer.write(encoder.encode(messageText));
432
+ } catch (error) {
433
+ console.error("Error forwarding message to SSE:", error);
434
+ }
281
435
  }
436
+ onMessage(event).catch(console.error);
282
437
  });
283
- ws.addEventListener("error", async (error) => {
284
- try {
285
- await writer.close();
286
- } catch (e) {
438
+ ws.addEventListener("error", (error) => {
439
+ async function onError(error2) {
440
+ try {
441
+ await writer.close();
442
+ } catch (e) {
443
+ }
287
444
  }
445
+ onError(error).catch(console.error);
288
446
  });
289
- ws.addEventListener("close", async () => {
290
- try {
291
- await writer.close();
292
- } catch (error) {
293
- console.error("Error closing SSE connection:", error);
447
+ ws.addEventListener("close", () => {
448
+ async function onClose() {
449
+ try {
450
+ await writer.close();
451
+ } catch (error) {
452
+ console.error("Error closing SSE connection:", error);
453
+ }
294
454
  }
455
+ onClose().catch(console.error);
295
456
  });
296
457
  return new Response(readable, {
297
458
  headers: {
@@ -310,30 +471,327 @@ data: ${JSON.stringify(result.data)}
310
471
  { status: 400 }
311
472
  );
312
473
  }
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 || "*"
474
+ const contentType = request.headers.get("content-type") || "";
475
+ if (!contentType.includes("application/json")) {
476
+ return new Response(`Unsupported content-type: ${contentType}`, {
477
+ status: 400
478
+ });
479
+ }
480
+ const contentLength = Number.parseInt(
481
+ request.headers.get("content-length") || "0",
482
+ 10
322
483
  );
323
- return new Response(response.body, {
324
- status: response.status,
325
- statusText: response.statusText,
326
- headers
484
+ if (contentLength > MAXIMUM_MESSAGE_SIZE_BYTES) {
485
+ return new Response(
486
+ `Request body too large: ${contentLength} bytes`,
487
+ {
488
+ status: 400
489
+ }
490
+ );
491
+ }
492
+ const id = namespace.idFromName(`sse:${sessionId}`);
493
+ const doStub = namespace.get(id);
494
+ const error = await doStub.onSSEMcpMessage(sessionId, request);
495
+ if (error) {
496
+ return new Response(error.message, {
497
+ status: 400,
498
+ headers: {
499
+ "Content-Type": "text/event-stream",
500
+ "Cache-Control": "no-cache",
501
+ Connection: "keep-alive",
502
+ "Access-Control-Allow-Origin": corsOptions?.origin || "*"
503
+ }
504
+ });
505
+ }
506
+ return new Response("Accepted", {
507
+ status: 202,
508
+ headers: {
509
+ "Content-Type": "text/event-stream",
510
+ "Cache-Control": "no-cache",
511
+ Connection: "keep-alive",
512
+ "Access-Control-Allow-Origin": corsOptions?.origin || "*"
513
+ }
327
514
  });
328
515
  }
329
516
  return new Response("Not Found", { status: 404 });
330
517
  }
331
518
  };
332
519
  }
520
+ static serve(path, {
521
+ binding = "MCP_OBJECT",
522
+ corsOptions
523
+ } = {}) {
524
+ let pathname = path;
525
+ if (path === "/") {
526
+ pathname = "/*";
527
+ }
528
+ const basePattern = new URLPattern({ pathname });
529
+ return {
530
+ async fetch(request, env, ctx) {
531
+ const corsResponse = handleCORS(request, corsOptions);
532
+ if (corsResponse) {
533
+ return corsResponse;
534
+ }
535
+ const url = new URL(request.url);
536
+ const bindingValue = env[binding];
537
+ if (bindingValue == null || typeof bindingValue !== "object") {
538
+ console.error(
539
+ `Could not find McpAgent binding for ${binding}. Did you update your wrangler configuration?`
540
+ );
541
+ return new Response("Invalid binding", { status: 500 });
542
+ }
543
+ if (bindingValue.toString() !== "[object DurableObjectNamespace]") {
544
+ return new Response("Invalid binding", { status: 500 });
545
+ }
546
+ const namespace = bindingValue;
547
+ if (request.method === "POST" && basePattern.test(url)) {
548
+ const acceptHeader = request.headers.get("accept");
549
+ if (!acceptHeader?.includes("application/json") || !acceptHeader.includes("text/event-stream")) {
550
+ const body2 = JSON.stringify({
551
+ jsonrpc: "2.0",
552
+ error: {
553
+ code: -32e3,
554
+ message: "Not Acceptable: Client must accept both application/json and text/event-stream"
555
+ },
556
+ id: null
557
+ });
558
+ return new Response(body2, { status: 406 });
559
+ }
560
+ const ct = request.headers.get("content-type");
561
+ if (!ct || !ct.includes("application/json")) {
562
+ const body2 = JSON.stringify({
563
+ jsonrpc: "2.0",
564
+ error: {
565
+ code: -32e3,
566
+ message: "Unsupported Media Type: Content-Type must be application/json"
567
+ },
568
+ id: null
569
+ });
570
+ return new Response(body2, { status: 415 });
571
+ }
572
+ const contentLength = Number.parseInt(
573
+ request.headers.get("content-length") ?? "0",
574
+ 10
575
+ );
576
+ if (contentLength > MAXIMUM_MESSAGE_SIZE_BYTES) {
577
+ const body2 = JSON.stringify({
578
+ jsonrpc: "2.0",
579
+ error: {
580
+ code: -32e3,
581
+ message: `Request body too large. Maximum size is ${MAXIMUM_MESSAGE_SIZE_BYTES} bytes`
582
+ },
583
+ id: null
584
+ });
585
+ return new Response(body2, { status: 413 });
586
+ }
587
+ let sessionId = request.headers.get("mcp-session-id");
588
+ let rawMessage;
589
+ try {
590
+ rawMessage = await request.json();
591
+ } catch (error) {
592
+ const body2 = JSON.stringify({
593
+ jsonrpc: "2.0",
594
+ error: {
595
+ code: -32700,
596
+ message: "Parse error: Invalid JSON"
597
+ },
598
+ id: null
599
+ });
600
+ return new Response(body2, { status: 400 });
601
+ }
602
+ let arrayMessage;
603
+ if (Array.isArray(rawMessage)) {
604
+ arrayMessage = rawMessage;
605
+ } else {
606
+ arrayMessage = [rawMessage];
607
+ }
608
+ let messages = [];
609
+ for (const msg of arrayMessage) {
610
+ if (!JSONRPCMessageSchema.safeParse(msg).success) {
611
+ const body2 = JSON.stringify({
612
+ jsonrpc: "2.0",
613
+ error: {
614
+ code: -32700,
615
+ message: "Parse error: Invalid JSON-RPC message"
616
+ },
617
+ id: null
618
+ });
619
+ return new Response(body2, { status: 400 });
620
+ }
621
+ }
622
+ messages = arrayMessage.map((msg) => JSONRPCMessageSchema.parse(msg));
623
+ const isInitializationRequest = messages.some(
624
+ (msg) => InitializeRequestSchema.safeParse(msg).success
625
+ );
626
+ if (isInitializationRequest && sessionId) {
627
+ const body2 = JSON.stringify({
628
+ jsonrpc: "2.0",
629
+ error: {
630
+ code: -32600,
631
+ message: "Invalid Request: Initialization requests must not include a sessionId"
632
+ },
633
+ id: null
634
+ });
635
+ return new Response(body2, { status: 400 });
636
+ }
637
+ if (isInitializationRequest && messages.length > 1) {
638
+ const body2 = JSON.stringify({
639
+ jsonrpc: "2.0",
640
+ error: {
641
+ code: -32600,
642
+ message: "Invalid Request: Only one initialization request is allowed"
643
+ },
644
+ id: null
645
+ });
646
+ return new Response(body2, { status: 400 });
647
+ }
648
+ if (!isInitializationRequest && !sessionId) {
649
+ const body2 = JSON.stringify({
650
+ jsonrpc: "2.0",
651
+ error: {
652
+ code: -32e3,
653
+ message: "Bad Request: Mcp-Session-Id header is required"
654
+ },
655
+ id: null
656
+ });
657
+ return new Response(body2, { status: 400 });
658
+ }
659
+ sessionId = sessionId ?? namespace.newUniqueId().toString();
660
+ const id = namespace.idFromName(`streamable-http:${sessionId}`);
661
+ const doStub = namespace.get(id);
662
+ const isInitialized = await doStub.isInitialized();
663
+ if (isInitializationRequest) {
664
+ await doStub.setInitialized();
665
+ } else if (!isInitialized) {
666
+ const body2 = JSON.stringify({
667
+ jsonrpc: "2.0",
668
+ error: {
669
+ code: -32001,
670
+ message: "Session not found"
671
+ },
672
+ id: null
673
+ });
674
+ return new Response(body2, { status: 404 });
675
+ }
676
+ const { readable, writable } = new TransformStream();
677
+ const writer = writable.getWriter();
678
+ const encoder = new TextEncoder();
679
+ const upgradeUrl = new URL(request.url);
680
+ upgradeUrl.pathname = "/streamable-http";
681
+ const response = await doStub.fetch(
682
+ new Request(upgradeUrl, {
683
+ headers: {
684
+ Upgrade: "websocket",
685
+ // Required by PartyServer
686
+ "x-partykit-room": sessionId
687
+ }
688
+ })
689
+ );
690
+ const ws = response.webSocket;
691
+ if (!ws) {
692
+ console.error("Failed to establish WebSocket connection");
693
+ await writer.close();
694
+ const body2 = JSON.stringify({
695
+ jsonrpc: "2.0",
696
+ error: {
697
+ code: -32001,
698
+ message: "Failed to establish WebSocket connection"
699
+ },
700
+ id: null
701
+ });
702
+ return new Response(body2, { status: 500 });
703
+ }
704
+ const requestIds = /* @__PURE__ */ new Set();
705
+ ws.accept();
706
+ ws.addEventListener("message", (event) => {
707
+ async function onMessage(event2) {
708
+ try {
709
+ const data = typeof event2.data === "string" ? event2.data : new TextDecoder().decode(event2.data);
710
+ const message = JSON.parse(data);
711
+ const result = JSONRPCMessageSchema.safeParse(message);
712
+ if (!result.success) {
713
+ return;
714
+ }
715
+ if (isJSONRPCResponse(result.data) || isJSONRPCError(result.data)) {
716
+ requestIds.delete(result.data.id);
717
+ }
718
+ const messageText = `event: message
719
+ data: ${JSON.stringify(result.data)}
720
+
721
+ `;
722
+ await writer.write(encoder.encode(messageText));
723
+ if (requestIds.size === 0) {
724
+ ws.close();
725
+ }
726
+ } catch (error) {
727
+ console.error("Error forwarding message to SSE:", error);
728
+ }
729
+ }
730
+ onMessage(event).catch(console.error);
731
+ });
732
+ ws.addEventListener("error", (error) => {
733
+ async function onError(error2) {
734
+ try {
735
+ await writer.close();
736
+ } catch (e) {
737
+ }
738
+ }
739
+ onError(error).catch(console.error);
740
+ });
741
+ ws.addEventListener("close", () => {
742
+ async function onClose() {
743
+ try {
744
+ await writer.close();
745
+ } catch (error) {
746
+ console.error("Error closing SSE connection:", error);
747
+ }
748
+ }
749
+ onClose().catch(console.error);
750
+ });
751
+ const hasOnlyNotificationsOrResponses = messages.every(
752
+ (msg) => isJSONRPCNotification(msg) || isJSONRPCResponse(msg)
753
+ );
754
+ if (hasOnlyNotificationsOrResponses) {
755
+ for (const message of messages) {
756
+ ws.send(JSON.stringify(message));
757
+ }
758
+ ws.close();
759
+ return new Response(null, { status: 202 });
760
+ }
761
+ for (const message of messages) {
762
+ if (isJSONRPCRequest(message)) {
763
+ requestIds.add(message.id);
764
+ }
765
+ ws.send(JSON.stringify(message));
766
+ }
767
+ return new Response(readable, {
768
+ headers: {
769
+ "Content-Type": "text/event-stream",
770
+ "Cache-Control": "no-cache",
771
+ Connection: "keep-alive",
772
+ "mcp-session-id": sessionId,
773
+ "Access-Control-Allow-Origin": corsOptions?.origin || "*"
774
+ },
775
+ status: 200
776
+ });
777
+ }
778
+ const body = JSON.stringify({
779
+ jsonrpc: "2.0",
780
+ error: {
781
+ code: -32e3,
782
+ message: "Method not allowed"
783
+ },
784
+ id: null
785
+ });
786
+ return new Response(body, { status: 405 });
787
+ }
788
+ };
789
+ }
333
790
  };
334
791
  _status = new WeakMap();
335
792
  _transport = new WeakMap();
336
- _connected = new WeakMap();
793
+ _transportType = new WeakMap();
794
+ _requestIdToConnectionId = new WeakMap();
337
795
  _agent = new WeakMap();
338
796
  _McpAgent_instances = new WeakSet();
339
797
  initialize_fn = async function() {
@@ -343,6 +801,7 @@ initialize_fn = async function() {
343
801
  __privateSet(this, _status, "started");
344
802
  });
345
803
  };
804
+ var McpAgent = _McpAgent;
346
805
  export {
347
806
  McpAgent
348
807
  };