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