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