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