agents 0.0.0-74a8c74 → 0.0.0-7bd597a

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,12 +1,25 @@
1
1
  import {
2
2
  Agent
3
- } from "../chunk-SZEXGW6W.js";
3
+ } from "../chunk-HD4VEHBA.js";
4
+ import "../chunk-Q5ZBHY4Z.js";
4
5
  import {
5
- SSEEdgeServerTransport
6
- } from "../chunk-EZ76ZGDB.js";
6
+ __privateAdd,
7
+ __privateGet,
8
+ __privateMethod,
9
+ __privateSet
10
+ } from "../chunk-HMLY7DHA.js";
7
11
 
8
12
  // src/mcp/index.ts
9
13
  import { DurableObject } from "cloudflare:workers";
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;
10
23
  function handleCORS(request, corsOptions) {
11
24
  const origin = request.headers.get("Origin") || "*";
12
25
  const corsHeaders = {
@@ -20,115 +33,776 @@ function handleCORS(request, corsOptions) {
20
33
  }
21
34
  return null;
22
35
  }
23
- var McpAgent = class extends DurableObject {
24
- /**
25
- * Since McpAgent's _aren't_ yet real "Agents" (they route differently, don't support
26
- * websockets, don't support hibernation), let's only expose a couple of the methods
27
- * to the outer class: initialState/state/setState/onStateUpdate/sql
28
- */
29
- #agent;
36
+ var _getWebSocket, _started;
37
+ var McpSSETransport = class {
38
+ constructor(getWebSocket) {
39
+ __privateAdd(this, _getWebSocket);
40
+ __privateAdd(this, _started, false);
41
+ __privateSet(this, _getWebSocket, getWebSocket);
42
+ }
43
+ async start() {
44
+ if (__privateGet(this, _started)) {
45
+ throw new Error("Transport already started");
46
+ }
47
+ __privateSet(this, _started, true);
48
+ }
49
+ async send(message) {
50
+ if (!__privateGet(this, _started)) {
51
+ throw new Error("Transport not started");
52
+ }
53
+ const websocket = __privateGet(this, _getWebSocket).call(this);
54
+ if (!websocket) {
55
+ throw new Error("WebSocket not connected");
56
+ }
57
+ try {
58
+ websocket.send(JSON.stringify(message));
59
+ } catch (error) {
60
+ this.onerror?.(error);
61
+ throw error;
62
+ }
63
+ }
64
+ async close() {
65
+ this.onclose?.();
66
+ }
67
+ };
68
+ _getWebSocket = new WeakMap();
69
+ _started = new WeakMap();
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 {
30
130
  constructor(ctx, env) {
131
+ var _a;
31
132
  super(ctx, env);
133
+ __privateAdd(this, _McpAgent_instances);
134
+ __privateAdd(this, _status, "zero");
135
+ __privateAdd(this, _transport);
136
+ __privateAdd(this, _transportType, "unset");
137
+ __privateAdd(this, _requestIdToConnectionId, /* @__PURE__ */ new Map());
138
+ /**
139
+ * Since McpAgent's _aren't_ yet real "Agents", let's only expose a couple of the methods
140
+ * to the outer class: initialState/state/setState/onStateUpdate/sql
141
+ */
142
+ __privateAdd(this, _agent);
143
+ this.initRun = false;
32
144
  const self = this;
33
- this.#agent = new class extends Agent {
34
- static options = {
35
- hibernate: false
36
- };
145
+ __privateSet(this, _agent, new (_a = class extends Agent {
37
146
  onStateUpdate(state, source) {
38
147
  return self.onStateUpdate(state, source);
39
148
  }
40
- }(ctx, env);
149
+ async onMessage(connection, message) {
150
+ return self.onMessage(connection, message);
151
+ }
152
+ }, _a.options = {
153
+ hibernate: true
154
+ }, _a)(ctx, env));
155
+ }
156
+ get mcp() {
157
+ return __privateGet(this, _agent).mcp;
41
158
  }
42
- /**
43
- * Agents API allowlist
44
- */
45
- initialState;
46
159
  get state() {
47
- if (this.initialState) this.#agent.initialState = this.initialState;
48
- return this.#agent.state;
160
+ return __privateGet(this, _agent).state;
49
161
  }
50
162
  sql(strings, ...values) {
51
- return this.#agent.sql(strings, ...values);
163
+ return __privateGet(this, _agent).sql(strings, ...values);
52
164
  }
53
165
  setState(state) {
54
- return this.#agent.setState(state);
166
+ return __privateGet(this, _agent).setState(state);
55
167
  }
56
168
  onStateUpdate(state, source) {
57
169
  }
58
- transport;
59
- props;
60
- initRun = false;
170
+ async onStart() {
171
+ var _a;
172
+ const self = this;
173
+ __privateSet(this, _agent, new (_a = class extends Agent {
174
+ constructor() {
175
+ super(...arguments);
176
+ this.initialState = self.initialState;
177
+ }
178
+ onStateUpdate(state, source) {
179
+ return self.onStateUpdate(state, source);
180
+ }
181
+ async onMessage(connection, event) {
182
+ return self.onMessage(connection, event);
183
+ }
184
+ }, _a.options = {
185
+ hibernate: true
186
+ }, _a)(this.ctx, this.env));
187
+ this.props = await this.ctx.storage.get("props");
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
+ }
203
+ }
61
204
  async _init(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
+ }
62
209
  this.props = props;
63
210
  if (!this.initRun) {
64
211
  this.initRun = true;
65
212
  await this.init();
66
213
  }
67
214
  }
68
- async onSSE(path) {
69
- this.transport = new SSEEdgeServerTransport(
70
- `${path}/message`,
71
- this.ctx.id.toString()
72
- );
73
- await this.server.connect(this.transport);
74
- return this.transport.sseResponse;
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
+ }
221
+ // Allow the worker to fetch a websocket connection to the agent
222
+ async fetch(request) {
223
+ if (__privateGet(this, _status) !== "started") {
224
+ await __privateMethod(this, _McpAgent_instances, initialize_fn).call(this);
225
+ }
226
+ if (request.headers.get("Upgrade") !== "websocket") {
227
+ return new Response("Expected WebSocket Upgrade request", {
228
+ status: 400
229
+ });
230
+ }
231
+ const url = new URL(request.url);
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
+ );
267
+ }
268
+ }
269
+ getWebSocket() {
270
+ const websockets = this.ctx.getWebSockets();
271
+ if (websockets.length === 0) {
272
+ return null;
273
+ }
274
+ return websockets[0];
275
+ }
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) {
308
+ if (__privateGet(this, _status) !== "started") {
309
+ await __privateMethod(this, _McpAgent_instances, initialize_fn).call(this);
310
+ }
311
+ if (__privateGet(this, _transportType) !== "sse") {
312
+ return new Error("Internal Server Error: Expected SSE protocol");
313
+ }
314
+ try {
315
+ const message = await request.json();
316
+ let parsedMessage;
317
+ try {
318
+ parsedMessage = JSONRPCMessageSchema.parse(message);
319
+ } catch (error) {
320
+ __privateGet(this, _transport)?.onerror?.(error);
321
+ throw error;
322
+ }
323
+ __privateGet(this, _transport)?.onmessage?.(parsedMessage);
324
+ return null;
325
+ } catch (error) {
326
+ console.error("Error forwarding message to SSE:", error);
327
+ __privateGet(this, _transport)?.onerror?.(error);
328
+ return error;
329
+ }
330
+ }
331
+ // Delegate all websocket events to the underlying agent
332
+ async webSocketMessage(ws, event) {
333
+ if (__privateGet(this, _status) !== "started") {
334
+ await __privateMethod(this, _McpAgent_instances, initialize_fn).call(this);
335
+ }
336
+ return await __privateGet(this, _agent).webSocketMessage(ws, event);
75
337
  }
76
- async onMCPMessage(request) {
77
- return this.transport.handlePostMessage(request);
338
+ // WebSocket event handlers for hibernation support
339
+ async webSocketError(ws, error) {
340
+ if (__privateGet(this, _status) !== "started") {
341
+ await __privateMethod(this, _McpAgent_instances, initialize_fn).call(this);
342
+ }
343
+ return await __privateGet(this, _agent).webSocketError(ws, error);
344
+ }
345
+ async webSocketClose(ws, code, reason, wasClean) {
346
+ if (__privateGet(this, _status) !== "started") {
347
+ await __privateMethod(this, _McpAgent_instances, initialize_fn).call(this);
348
+ }
349
+ return await __privateGet(this, _agent).webSocketClose(ws, code, reason, wasClean);
78
350
  }
79
351
  static mount(path, {
80
352
  binding = "MCP_OBJECT",
81
353
  corsOptions
82
354
  } = {}) {
83
- const basePattern = new URLPattern({ pathname: path });
84
- const messagePattern = new URLPattern({ pathname: `${path}/message` });
355
+ return _McpAgent.serveSSE(path, { binding, corsOptions });
356
+ }
357
+ static serveSSE(path, {
358
+ binding = "MCP_OBJECT",
359
+ corsOptions
360
+ } = {}) {
361
+ let pathname = path;
362
+ if (path === "/") {
363
+ pathname = "/*";
364
+ }
365
+ const basePattern = new URLPattern({ pathname });
366
+ const messagePattern = new URLPattern({ pathname: `${pathname}/message` });
85
367
  return {
86
- fetch: async (request, env, ctx) => {
368
+ async fetch(request, env, ctx) {
87
369
  const corsResponse = handleCORS(request, corsOptions);
88
370
  if (corsResponse) return corsResponse;
89
371
  const url = new URL(request.url);
90
- 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;
91
383
  if (request.method === "GET" && basePattern.test(url)) {
92
- const object = namespace.get(namespace.newUniqueId());
93
- await object._init(ctx.props);
94
- const response = await object.onSSE(path);
95
- const headerObj = {};
96
- response.headers.forEach((value, key) => {
97
- headerObj[key] = value;
384
+ const sessionId = url.searchParams.get("sessionId") || namespace.newUniqueId().toString();
385
+ const { readable, writable } = new TransformStream();
386
+ const writer = writable.getWriter();
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;
392
+ const endpointMessage = `event: endpoint
393
+ data: ${relativeUrlWithSession}
394
+
395
+ `;
396
+ writer.write(encoder.encode(endpointMessage));
397
+ const id = namespace.idFromName(`sse:${sessionId}`);
398
+ const doStub = namespace.get(id);
399
+ await doStub._init(ctx.props);
400
+ const upgradeUrl = new URL(request.url);
401
+ upgradeUrl.pathname = "/sse";
402
+ const response = await doStub.fetch(
403
+ new Request(upgradeUrl, {
404
+ headers: {
405
+ Upgrade: "websocket",
406
+ // Required by PartyServer
407
+ "x-partykit-room": sessionId
408
+ }
409
+ })
410
+ );
411
+ const ws = response.webSocket;
412
+ if (!ws) {
413
+ console.error("Failed to establish WebSocket connection");
414
+ await writer.close();
415
+ return new Response("Failed to establish WebSocket connection", {
416
+ status: 500
417
+ });
418
+ }
419
+ ws.accept();
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
429
+ data: ${JSON.stringify(result.data)}
430
+
431
+ `;
432
+ await writer.write(encoder.encode(messageText));
433
+ } catch (error) {
434
+ console.error("Error forwarding message to SSE:", error);
435
+ }
436
+ }
437
+ onMessage(event).catch(console.error);
438
+ });
439
+ ws.addEventListener("error", (error) => {
440
+ async function onError(error2) {
441
+ try {
442
+ await writer.close();
443
+ } catch (e) {
444
+ }
445
+ }
446
+ onError(error).catch(console.error);
98
447
  });
99
- headerObj["Access-Control-Allow-Origin"] = corsOptions?.origin || "*";
100
- return new Response(response.body, {
101
- status: response.status,
102
- statusText: response.statusText,
103
- headers: headerObj
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
+ }
455
+ }
456
+ onClose().catch(console.error);
457
+ });
458
+ return new Response(readable, {
459
+ headers: {
460
+ "Content-Type": "text/event-stream",
461
+ "Cache-Control": "no-cache",
462
+ Connection: "keep-alive",
463
+ "Access-Control-Allow-Origin": corsOptions?.origin || "*"
464
+ }
104
465
  });
105
466
  }
106
467
  if (request.method === "POST" && messagePattern.test(url)) {
107
468
  const sessionId = url.searchParams.get("sessionId");
108
469
  if (!sessionId) {
109
470
  return new Response(
110
- `Missing sessionId. Expected POST to ${path} to initiate new one`,
471
+ `Missing sessionId. Expected POST to ${pathname} to initiate new one`,
111
472
  { status: 400 }
112
473
  );
113
474
  }
114
- const object = namespace.get(namespace.idFromString(sessionId));
115
- const response = await object.onMCPMessage(request);
116
- const headerObj = {};
117
- response.headers.forEach((value, key) => {
118
- headerObj[key] = value;
119
- });
120
- headerObj["Access-Control-Allow-Origin"] = corsOptions?.origin || "*";
121
- return new Response(response.body, {
122
- status: response.status,
123
- statusText: response.statusText,
124
- headers: headerObj
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
484
+ );
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
+ }
125
515
  });
126
516
  }
127
517
  return new Response("Not Found", { status: 404 });
128
518
  }
129
519
  };
130
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.setInitialized();
666
+ } else if (!isInitialized) {
667
+ const body2 = JSON.stringify({
668
+ jsonrpc: "2.0",
669
+ error: {
670
+ code: -32001,
671
+ message: "Session not found"
672
+ },
673
+ id: null
674
+ });
675
+ return new Response(body2, { status: 404 });
676
+ }
677
+ const { readable, writable } = new TransformStream();
678
+ const writer = writable.getWriter();
679
+ const encoder = new TextEncoder();
680
+ const upgradeUrl = new URL(request.url);
681
+ upgradeUrl.pathname = "/streamable-http";
682
+ const response = await doStub.fetch(
683
+ new Request(upgradeUrl, {
684
+ headers: {
685
+ Upgrade: "websocket",
686
+ // Required by PartyServer
687
+ "x-partykit-room": sessionId
688
+ }
689
+ })
690
+ );
691
+ const ws = response.webSocket;
692
+ if (!ws) {
693
+ console.error("Failed to establish WebSocket connection");
694
+ await writer.close();
695
+ const body2 = JSON.stringify({
696
+ jsonrpc: "2.0",
697
+ error: {
698
+ code: -32001,
699
+ message: "Failed to establish WebSocket connection"
700
+ },
701
+ id: null
702
+ });
703
+ return new Response(body2, { status: 500 });
704
+ }
705
+ const requestIds = /* @__PURE__ */ new Set();
706
+ ws.accept();
707
+ ws.addEventListener("message", (event) => {
708
+ async function onMessage(event2) {
709
+ try {
710
+ const data = typeof event2.data === "string" ? event2.data : new TextDecoder().decode(event2.data);
711
+ const message = JSON.parse(data);
712
+ const result = JSONRPCMessageSchema.safeParse(message);
713
+ if (!result.success) {
714
+ return;
715
+ }
716
+ if (isJSONRPCResponse(result.data) || isJSONRPCError(result.data)) {
717
+ requestIds.delete(result.data.id);
718
+ }
719
+ const messageText = `event: message
720
+ data: ${JSON.stringify(result.data)}
721
+
722
+ `;
723
+ await writer.write(encoder.encode(messageText));
724
+ if (requestIds.size === 0) {
725
+ ws.close();
726
+ }
727
+ } catch (error) {
728
+ console.error("Error forwarding message to SSE:", error);
729
+ }
730
+ }
731
+ onMessage(event).catch(console.error);
732
+ });
733
+ ws.addEventListener("error", (error) => {
734
+ async function onError(error2) {
735
+ try {
736
+ await writer.close();
737
+ } catch (e) {
738
+ }
739
+ }
740
+ onError(error).catch(console.error);
741
+ });
742
+ ws.addEventListener("close", () => {
743
+ async function onClose() {
744
+ try {
745
+ await writer.close();
746
+ } catch (error) {
747
+ console.error("Error closing SSE connection:", error);
748
+ }
749
+ }
750
+ onClose().catch(console.error);
751
+ });
752
+ const hasOnlyNotificationsOrResponses = messages.every(
753
+ (msg) => isJSONRPCNotification(msg) || isJSONRPCResponse(msg)
754
+ );
755
+ if (hasOnlyNotificationsOrResponses) {
756
+ for (const message of messages) {
757
+ ws.send(JSON.stringify(message));
758
+ }
759
+ ws.close();
760
+ return new Response(null, { status: 202 });
761
+ }
762
+ for (const message of messages) {
763
+ if (isJSONRPCRequest(message)) {
764
+ requestIds.add(message.id);
765
+ }
766
+ ws.send(JSON.stringify(message));
767
+ }
768
+ return new Response(readable, {
769
+ headers: {
770
+ "Content-Type": "text/event-stream",
771
+ "Cache-Control": "no-cache",
772
+ Connection: "keep-alive",
773
+ "mcp-session-id": sessionId,
774
+ "Access-Control-Allow-Origin": corsOptions?.origin || "*"
775
+ },
776
+ status: 200
777
+ });
778
+ }
779
+ const body = JSON.stringify({
780
+ jsonrpc: "2.0",
781
+ error: {
782
+ code: -32e3,
783
+ message: "Method not allowed"
784
+ },
785
+ id: null
786
+ });
787
+ return new Response(body, { status: 405 });
788
+ }
789
+ };
790
+ }
791
+ };
792
+ _status = new WeakMap();
793
+ _transport = new WeakMap();
794
+ _transportType = new WeakMap();
795
+ _requestIdToConnectionId = new WeakMap();
796
+ _agent = new WeakMap();
797
+ _McpAgent_instances = new WeakSet();
798
+ initialize_fn = async function() {
799
+ await this.ctx.blockConcurrencyWhile(async () => {
800
+ __privateSet(this, _status, "starting");
801
+ await this.onStart();
802
+ __privateSet(this, _status, "started");
803
+ });
131
804
  };
805
+ var McpAgent = _McpAgent;
132
806
  export {
133
807
  McpAgent
134
808
  };