agents 0.0.0-25aeaf2 → 0.0.0-263787c
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 +128 -22
- package/dist/ai-chat-agent.d.ts +35 -6
- package/dist/ai-chat-agent.js +149 -117
- package/dist/ai-chat-agent.js.map +1 -1
- package/dist/ai-react.d.ts +13 -10
- package/dist/ai-react.js +27 -29
- package/dist/ai-react.js.map +1 -1
- package/dist/{chunk-25YDMV4H.js → chunk-HY7ZLHJB.js} +178 -44
- package/dist/chunk-HY7ZLHJB.js.map +1 -0
- package/dist/chunk-JXN5WZFQ.js +1287 -0
- package/dist/chunk-JXN5WZFQ.js.map +1 -0
- package/dist/{chunk-RN4SNE73.js → chunk-KUH345EY.js} +17 -34
- package/dist/chunk-KUH345EY.js.map +1 -0
- package/dist/{chunk-D6UOOELW.js → chunk-PVQZBKN7.js} +15 -15
- package/dist/chunk-PVQZBKN7.js.map +1 -0
- package/dist/client-DgyzBU_8.d.ts +4601 -0
- package/dist/client.d.ts +10 -3
- package/dist/client.js +1 -2
- package/dist/index-BCJclX6q.d.ts +615 -0
- package/dist/index.d.ts +35 -361
- package/dist/index.js +10 -5
- package/dist/mcp/client.d.ts +9 -781
- package/dist/mcp/client.js +1 -2
- package/dist/mcp/do-oauth-client-provider.d.ts +3 -3
- package/dist/mcp/do-oauth-client-provider.js +1 -2
- package/dist/mcp/index.d.ts +48 -11
- package/dist/mcp/index.js +317 -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 +79 -11
- package/dist/react.js +16 -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 -71
- package/src/index.ts +895 -222
- package/dist/chunk-25YDMV4H.js.map +0 -1
- package/dist/chunk-D6UOOELW.js.map +0 -1
- package/dist/chunk-HMLY7DHA.js +0 -16
- package/dist/chunk-RN4SNE73.js.map +0 -1
- package/dist/chunk-YFPCCSZO.js +0 -787
- package/dist/chunk-YFPCCSZO.js.map +0 -1
- /package/dist/{chunk-HMLY7DHA.js.map → observability/index.js.map} +0 -0
package/dist/mcp/index.js
CHANGED
|
@@ -1,61 +1,62 @@
|
|
|
1
1
|
import {
|
|
2
2
|
Agent
|
|
3
|
-
} from "../chunk-
|
|
4
|
-
import "../chunk-D6UOOELW.js";
|
|
5
|
-
import "../chunk-RN4SNE73.js";
|
|
6
|
-
import "../chunk-25YDMV4H.js";
|
|
3
|
+
} from "../chunk-JXN5WZFQ.js";
|
|
7
4
|
import {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
5
|
+
SSEEdgeClientTransport,
|
|
6
|
+
StreamableHTTPEdgeClientTransport
|
|
7
|
+
} from "../chunk-HY7ZLHJB.js";
|
|
8
|
+
import "../chunk-PVQZBKN7.js";
|
|
9
|
+
import "../chunk-KUH345EY.js";
|
|
13
10
|
|
|
14
11
|
// src/mcp/index.ts
|
|
15
12
|
import { DurableObject } from "cloudflare:workers";
|
|
16
13
|
import {
|
|
17
14
|
InitializeRequestSchema,
|
|
15
|
+
JSONRPCMessageSchema,
|
|
18
16
|
isJSONRPCError,
|
|
19
17
|
isJSONRPCNotification,
|
|
20
18
|
isJSONRPCRequest,
|
|
21
|
-
isJSONRPCResponse
|
|
22
|
-
|
|
19
|
+
isJSONRPCResponse
|
|
20
|
+
} from "@modelcontextprotocol/sdk/types.js";
|
|
21
|
+
import {
|
|
22
|
+
ElicitRequestSchema
|
|
23
23
|
} from "@modelcontextprotocol/sdk/types.js";
|
|
24
24
|
var MAXIMUM_MESSAGE_SIZE_BYTES = 4 * 1024 * 1024;
|
|
25
|
-
function corsHeaders(
|
|
25
|
+
function corsHeaders(_request, corsOptions = {}) {
|
|
26
26
|
const origin = "*";
|
|
27
27
|
return {
|
|
28
|
-
"Access-Control-Allow-
|
|
28
|
+
"Access-Control-Allow-Headers": corsOptions.headers || "Content-Type, mcp-session-id, mcp-protocol-version",
|
|
29
29
|
"Access-Control-Allow-Methods": corsOptions.methods || "GET, POST, OPTIONS",
|
|
30
|
-
"Access-Control-Allow-
|
|
31
|
-
"Access-Control-
|
|
32
|
-
"Access-Control-
|
|
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()
|
|
33
33
|
};
|
|
34
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
|
+
}
|
|
35
38
|
function handleCORS(request, corsOptions) {
|
|
36
39
|
if (request.method === "OPTIONS") {
|
|
37
40
|
return new Response(null, { headers: corsHeaders(request, corsOptions) });
|
|
38
41
|
}
|
|
39
42
|
return null;
|
|
40
43
|
}
|
|
41
|
-
var _getWebSocket, _started;
|
|
42
44
|
var McpSSETransport = class {
|
|
43
45
|
constructor(getWebSocket) {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
__privateSet(this, _getWebSocket, getWebSocket);
|
|
46
|
+
this._started = false;
|
|
47
|
+
this._getWebSocket = getWebSocket;
|
|
47
48
|
}
|
|
48
49
|
async start() {
|
|
49
|
-
if (
|
|
50
|
+
if (this._started) {
|
|
50
51
|
throw new Error("Transport already started");
|
|
51
52
|
}
|
|
52
|
-
|
|
53
|
+
this._started = true;
|
|
53
54
|
}
|
|
54
55
|
async send(message) {
|
|
55
|
-
if (!
|
|
56
|
+
if (!this._started) {
|
|
56
57
|
throw new Error("Transport not started");
|
|
57
58
|
}
|
|
58
|
-
const websocket =
|
|
59
|
+
const websocket = this._getWebSocket();
|
|
59
60
|
if (!websocket) {
|
|
60
61
|
throw new Error("WebSocket not connected");
|
|
61
62
|
}
|
|
@@ -70,52 +71,40 @@ var McpSSETransport = class {
|
|
|
70
71
|
this.onclose?.();
|
|
71
72
|
}
|
|
72
73
|
};
|
|
73
|
-
_getWebSocket = new WeakMap();
|
|
74
|
-
_started = new WeakMap();
|
|
75
|
-
var _getWebSocketForGetRequest, _getWebSocketForMessageID, _notifyResponseIdSent, _started2;
|
|
76
74
|
var McpStreamableHttpTransport = class {
|
|
77
75
|
constructor(getWebSocketForMessageID, notifyResponseIdSent) {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
__privateAdd(this, _getWebSocketForMessageID);
|
|
83
|
-
// Notify the server that a response has been sent for a given message id
|
|
84
|
-
// so that it may clean up it's mapping of message ids to connections
|
|
85
|
-
// once they are no longer needed
|
|
86
|
-
__privateAdd(this, _notifyResponseIdSent);
|
|
87
|
-
__privateAdd(this, _started2, false);
|
|
88
|
-
__privateSet(this, _getWebSocketForMessageID, getWebSocketForMessageID);
|
|
89
|
-
__privateSet(this, _notifyResponseIdSent, notifyResponseIdSent);
|
|
90
|
-
__privateSet(this, _getWebSocketForGetRequest, () => null);
|
|
76
|
+
this._started = false;
|
|
77
|
+
this._getWebSocketForMessageID = getWebSocketForMessageID;
|
|
78
|
+
this._notifyResponseIdSent = notifyResponseIdSent;
|
|
79
|
+
this._getWebSocketForGetRequest = () => null;
|
|
91
80
|
}
|
|
92
81
|
async start() {
|
|
93
|
-
if (
|
|
82
|
+
if (this._started) {
|
|
94
83
|
throw new Error("Transport already started");
|
|
95
84
|
}
|
|
96
|
-
|
|
85
|
+
this._started = true;
|
|
97
86
|
}
|
|
98
87
|
async send(message) {
|
|
99
|
-
if (!
|
|
88
|
+
if (!this._started) {
|
|
100
89
|
throw new Error("Transport not started");
|
|
101
90
|
}
|
|
102
91
|
let websocket = null;
|
|
103
92
|
if (isJSONRPCResponse(message) || isJSONRPCError(message)) {
|
|
104
|
-
websocket =
|
|
93
|
+
websocket = this._getWebSocketForMessageID(message.id.toString());
|
|
105
94
|
if (!websocket) {
|
|
106
95
|
throw new Error(
|
|
107
96
|
`Could not find WebSocket for message id: ${message.id}`
|
|
108
97
|
);
|
|
109
98
|
}
|
|
110
99
|
} else if (isJSONRPCRequest(message)) {
|
|
111
|
-
websocket =
|
|
100
|
+
websocket = this._getWebSocketForGetRequest();
|
|
112
101
|
} else if (isJSONRPCNotification(message)) {
|
|
113
102
|
websocket = null;
|
|
114
103
|
}
|
|
115
104
|
try {
|
|
116
105
|
websocket?.send(JSON.stringify(message));
|
|
117
106
|
if (isJSONRPCResponse(message)) {
|
|
118
|
-
|
|
107
|
+
this._notifyResponseIdSent(message.id.toString());
|
|
119
108
|
}
|
|
120
109
|
} catch (error) {
|
|
121
110
|
this.onerror?.(error);
|
|
@@ -126,28 +115,16 @@ var McpStreamableHttpTransport = class {
|
|
|
126
115
|
this.onclose?.();
|
|
127
116
|
}
|
|
128
117
|
};
|
|
129
|
-
|
|
130
|
-
_getWebSocketForMessageID = new WeakMap();
|
|
131
|
-
_notifyResponseIdSent = new WeakMap();
|
|
132
|
-
_started2 = new WeakMap();
|
|
133
|
-
var _status, _transport, _transportType, _requestIdToConnectionId, _agent, _McpAgent_instances, initialize_fn;
|
|
134
|
-
var _McpAgent = class _McpAgent extends DurableObject {
|
|
118
|
+
var McpAgent = class _McpAgent extends DurableObject {
|
|
135
119
|
constructor(ctx, env) {
|
|
136
120
|
var _a;
|
|
137
121
|
super(ctx, env);
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
__privateAdd(this, _transportType, "unset");
|
|
142
|
-
__privateAdd(this, _requestIdToConnectionId, /* @__PURE__ */ new Map());
|
|
143
|
-
/**
|
|
144
|
-
* Since McpAgent's _aren't_ yet real "Agents", let's only expose a couple of the methods
|
|
145
|
-
* to the outer class: initialState/state/setState/onStateUpdate/sql
|
|
146
|
-
*/
|
|
147
|
-
__privateAdd(this, _agent);
|
|
122
|
+
this._status = "zero";
|
|
123
|
+
this._transportType = "unset";
|
|
124
|
+
this._requestIdToConnectionId = /* @__PURE__ */ new Map();
|
|
148
125
|
this.initRun = false;
|
|
149
126
|
const self = this;
|
|
150
|
-
|
|
127
|
+
this._agent = new (_a = class extends Agent {
|
|
151
128
|
onStateUpdate(state, source) {
|
|
152
129
|
return self.onStateUpdate(state, source);
|
|
153
130
|
}
|
|
@@ -156,26 +133,66 @@ var _McpAgent = class _McpAgent extends DurableObject {
|
|
|
156
133
|
}
|
|
157
134
|
}, _a.options = {
|
|
158
135
|
hibernate: true
|
|
159
|
-
}, _a)(ctx, env)
|
|
136
|
+
}, _a)(ctx, env);
|
|
160
137
|
}
|
|
161
138
|
get mcp() {
|
|
162
|
-
return
|
|
139
|
+
return this._agent.mcp;
|
|
163
140
|
}
|
|
164
141
|
get state() {
|
|
165
|
-
return
|
|
142
|
+
return this._agent.state;
|
|
166
143
|
}
|
|
167
144
|
sql(strings, ...values) {
|
|
168
|
-
return
|
|
145
|
+
return this._agent.sql(strings, ...values);
|
|
169
146
|
}
|
|
170
147
|
setState(state) {
|
|
171
|
-
return
|
|
148
|
+
return this._agent.setState(state);
|
|
172
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
|
|
173
190
|
onStateUpdate(state, source) {
|
|
174
191
|
}
|
|
175
192
|
async onStart() {
|
|
176
193
|
var _a;
|
|
177
194
|
const self = this;
|
|
178
|
-
|
|
195
|
+
this._agent = new (_a = class extends Agent {
|
|
179
196
|
constructor() {
|
|
180
197
|
super(...arguments);
|
|
181
198
|
this.initialState = self.initialState;
|
|
@@ -188,33 +205,50 @@ var _McpAgent = class _McpAgent extends DurableObject {
|
|
|
188
205
|
}
|
|
189
206
|
}, _a.options = {
|
|
190
207
|
hibernate: true
|
|
191
|
-
}, _a)(this.ctx, this.env)
|
|
208
|
+
}, _a)(this.ctx, this.env);
|
|
192
209
|
this.props = await this.ctx.storage.get("props");
|
|
193
|
-
|
|
210
|
+
this._transportType = await this.ctx.storage.get(
|
|
194
211
|
"transportType"
|
|
195
|
-
)
|
|
212
|
+
);
|
|
196
213
|
await this._init(this.props);
|
|
197
214
|
const server = await this.server;
|
|
198
|
-
if (
|
|
199
|
-
|
|
200
|
-
await server.connect(
|
|
201
|
-
} else if (
|
|
202
|
-
|
|
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(
|
|
203
220
|
(id) => this.getWebSocketForResponseID(id),
|
|
204
|
-
(id) =>
|
|
205
|
-
)
|
|
206
|
-
await server.connect(
|
|
221
|
+
(id) => this._requestIdToConnectionId.delete(id)
|
|
222
|
+
);
|
|
223
|
+
await server.connect(this._transport);
|
|
207
224
|
}
|
|
208
225
|
}
|
|
226
|
+
/**
|
|
227
|
+
* Handle errors that occur during initialization or operation.
|
|
228
|
+
* Override this method to provide custom error handling.
|
|
229
|
+
* @param error - The error that occurred
|
|
230
|
+
* @returns An error response object with status code and message
|
|
231
|
+
*/
|
|
232
|
+
onError(error) {
|
|
233
|
+
console.error("McpAgent error:", error);
|
|
234
|
+
return {
|
|
235
|
+
status: 500,
|
|
236
|
+
message: error.message || "An unexpected error occurred during initialization"
|
|
237
|
+
};
|
|
238
|
+
}
|
|
209
239
|
async _init(props) {
|
|
210
|
-
await this.
|
|
240
|
+
await this.updateProps(props);
|
|
211
241
|
if (!this.ctx.storage.get("transportType")) {
|
|
212
242
|
await this.ctx.storage.put("transportType", "unset");
|
|
213
243
|
}
|
|
214
|
-
this.props = props;
|
|
215
244
|
if (!this.initRun) {
|
|
216
245
|
this.initRun = true;
|
|
217
|
-
|
|
246
|
+
try {
|
|
247
|
+
await this.init();
|
|
248
|
+
} catch (error) {
|
|
249
|
+
const errorResponse = this.onError(error);
|
|
250
|
+
throw new Error(`Initialization failed: ${errorResponse.message}`);
|
|
251
|
+
}
|
|
218
252
|
}
|
|
219
253
|
}
|
|
220
254
|
async setInitialized() {
|
|
@@ -223,10 +257,21 @@ var _McpAgent = class _McpAgent extends DurableObject {
|
|
|
223
257
|
async isInitialized() {
|
|
224
258
|
return await this.ctx.storage.get("initialized") === true;
|
|
225
259
|
}
|
|
260
|
+
async updateProps(props) {
|
|
261
|
+
await this.ctx.storage.put("props", props ?? {});
|
|
262
|
+
this.props = props;
|
|
263
|
+
}
|
|
264
|
+
async _initialize() {
|
|
265
|
+
await this.ctx.blockConcurrencyWhile(async () => {
|
|
266
|
+
this._status = "starting";
|
|
267
|
+
await this.onStart();
|
|
268
|
+
this._status = "started";
|
|
269
|
+
});
|
|
270
|
+
}
|
|
226
271
|
// Allow the worker to fetch a websocket connection to the agent
|
|
227
272
|
async fetch(request) {
|
|
228
|
-
if (
|
|
229
|
-
await
|
|
273
|
+
if (this._status !== "started") {
|
|
274
|
+
await this._initialize();
|
|
230
275
|
}
|
|
231
276
|
if (request.headers.get("Upgrade") !== "websocket") {
|
|
232
277
|
return new Response("Expected WebSocket Upgrade request", {
|
|
@@ -243,24 +288,24 @@ var _McpAgent = class _McpAgent extends DurableObject {
|
|
|
243
288
|
return new Response("Websocket already connected", { status: 400 });
|
|
244
289
|
}
|
|
245
290
|
await this.ctx.storage.put("transportType", "sse");
|
|
246
|
-
|
|
247
|
-
if (!
|
|
248
|
-
|
|
249
|
-
await server.connect(
|
|
291
|
+
this._transportType = "sse";
|
|
292
|
+
if (!this._transport) {
|
|
293
|
+
this._transport = new McpSSETransport(() => this.getWebSocket());
|
|
294
|
+
await server.connect(this._transport);
|
|
250
295
|
}
|
|
251
|
-
return
|
|
296
|
+
return this._agent.fetch(request);
|
|
252
297
|
}
|
|
253
298
|
case "/streamable-http": {
|
|
254
|
-
if (!
|
|
255
|
-
|
|
299
|
+
if (!this._transport) {
|
|
300
|
+
this._transport = new McpStreamableHttpTransport(
|
|
256
301
|
(id) => this.getWebSocketForResponseID(id),
|
|
257
|
-
(id) =>
|
|
258
|
-
)
|
|
259
|
-
await server.connect(
|
|
302
|
+
(id) => this._requestIdToConnectionId.delete(id)
|
|
303
|
+
);
|
|
304
|
+
await server.connect(this._transport);
|
|
260
305
|
}
|
|
261
306
|
await this.ctx.storage.put("transportType", "streamable-http");
|
|
262
|
-
|
|
263
|
-
return
|
|
307
|
+
this._transportType = "streamable-http";
|
|
308
|
+
return this._agent.fetch(request);
|
|
264
309
|
}
|
|
265
310
|
default:
|
|
266
311
|
return new Response(
|
|
@@ -279,19 +324,19 @@ var _McpAgent = class _McpAgent extends DurableObject {
|
|
|
279
324
|
return websockets[0];
|
|
280
325
|
}
|
|
281
326
|
getWebSocketForResponseID(id) {
|
|
282
|
-
const connectionId =
|
|
327
|
+
const connectionId = this._requestIdToConnectionId.get(id);
|
|
283
328
|
if (connectionId === void 0) {
|
|
284
329
|
return null;
|
|
285
330
|
}
|
|
286
|
-
return
|
|
331
|
+
return this._agent.getConnection(connectionId) ?? null;
|
|
287
332
|
}
|
|
288
333
|
// All messages received here. This is currently never called
|
|
289
334
|
async onMessage(connection, event) {
|
|
290
|
-
if (
|
|
335
|
+
if (this._transportType !== "streamable-http") {
|
|
291
336
|
const err = new Error(
|
|
292
337
|
"Internal Server Error: Expected streamable-http protocol"
|
|
293
338
|
);
|
|
294
|
-
|
|
339
|
+
this._transport?.onerror?.(err);
|
|
295
340
|
return;
|
|
296
341
|
}
|
|
297
342
|
let message;
|
|
@@ -299,59 +344,125 @@ var _McpAgent = class _McpAgent extends DurableObject {
|
|
|
299
344
|
const data = typeof event === "string" ? event : new TextDecoder().decode(event);
|
|
300
345
|
message = JSONRPCMessageSchema.parse(JSON.parse(data));
|
|
301
346
|
} catch (error) {
|
|
302
|
-
|
|
347
|
+
this._transport?.onerror?.(error);
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
350
|
+
if (await this._handleElicitationResponse(message)) {
|
|
303
351
|
return;
|
|
304
352
|
}
|
|
305
353
|
if (isJSONRPCRequest(message)) {
|
|
306
|
-
|
|
354
|
+
this._requestIdToConnectionId.set(message.id.toString(), connection.id);
|
|
355
|
+
}
|
|
356
|
+
this._transport?.onmessage?.(message);
|
|
357
|
+
}
|
|
358
|
+
/**
|
|
359
|
+
* Wait for elicitation response through storage polling
|
|
360
|
+
*/
|
|
361
|
+
async _waitForElicitationResponse(requestId) {
|
|
362
|
+
const startTime = Date.now();
|
|
363
|
+
const timeout = 6e4;
|
|
364
|
+
try {
|
|
365
|
+
while (Date.now() - startTime < timeout) {
|
|
366
|
+
const response = await this.ctx.storage.get(
|
|
367
|
+
`elicitation:response:${requestId}`
|
|
368
|
+
);
|
|
369
|
+
if (response) {
|
|
370
|
+
await this.ctx.storage.delete(`elicitation:${requestId}`);
|
|
371
|
+
await this.ctx.storage.delete(`elicitation:response:${requestId}`);
|
|
372
|
+
return response;
|
|
373
|
+
}
|
|
374
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
375
|
+
}
|
|
376
|
+
throw new Error("Elicitation request timed out");
|
|
377
|
+
} finally {
|
|
378
|
+
await this.ctx.storage.delete(`elicitation:${requestId}`);
|
|
379
|
+
await this.ctx.storage.delete(`elicitation:response:${requestId}`);
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
/**
|
|
383
|
+
* Handle elicitation responses */
|
|
384
|
+
async _handleElicitationResponse(message) {
|
|
385
|
+
if (isJSONRPCResponse(message) && message.result) {
|
|
386
|
+
const requestId = message.id?.toString();
|
|
387
|
+
if (!requestId || !requestId.startsWith("elicit_")) return false;
|
|
388
|
+
const pendingRequest = await this.ctx.storage.get(
|
|
389
|
+
`elicitation:${requestId}`
|
|
390
|
+
);
|
|
391
|
+
if (!pendingRequest) return false;
|
|
392
|
+
await this.ctx.storage.put(
|
|
393
|
+
`elicitation:response:${requestId}`,
|
|
394
|
+
message.result
|
|
395
|
+
);
|
|
396
|
+
return true;
|
|
397
|
+
}
|
|
398
|
+
if (isJSONRPCError(message)) {
|
|
399
|
+
const requestId = message.id?.toString();
|
|
400
|
+
if (!requestId || !requestId.startsWith("elicit_")) return false;
|
|
401
|
+
const pendingRequest = await this.ctx.storage.get(
|
|
402
|
+
`elicitation:${requestId}`
|
|
403
|
+
);
|
|
404
|
+
if (!pendingRequest) return false;
|
|
405
|
+
const errorResult = {
|
|
406
|
+
action: "cancel",
|
|
407
|
+
content: {
|
|
408
|
+
error: message.error.message || "Elicitation request failed"
|
|
409
|
+
}
|
|
410
|
+
};
|
|
411
|
+
await this.ctx.storage.put(
|
|
412
|
+
`elicitation:response:${requestId}`,
|
|
413
|
+
errorResult
|
|
414
|
+
);
|
|
415
|
+
return true;
|
|
307
416
|
}
|
|
308
|
-
|
|
417
|
+
return false;
|
|
309
418
|
}
|
|
310
419
|
// All messages received over SSE after the initial connection has been established
|
|
311
420
|
// will be passed here
|
|
312
|
-
async onSSEMcpMessage(
|
|
313
|
-
if (
|
|
314
|
-
await
|
|
421
|
+
async onSSEMcpMessage(_sessionId, messageBody) {
|
|
422
|
+
if (this._status !== "started") {
|
|
423
|
+
await this._initialize();
|
|
315
424
|
}
|
|
316
|
-
if (
|
|
425
|
+
if (this._transportType !== "sse") {
|
|
317
426
|
return new Error("Internal Server Error: Expected SSE protocol");
|
|
318
427
|
}
|
|
319
428
|
try {
|
|
320
|
-
const message = await request.json();
|
|
321
429
|
let parsedMessage;
|
|
322
430
|
try {
|
|
323
|
-
parsedMessage = JSONRPCMessageSchema.parse(
|
|
431
|
+
parsedMessage = JSONRPCMessageSchema.parse(messageBody);
|
|
324
432
|
} catch (error) {
|
|
325
|
-
|
|
433
|
+
this._transport?.onerror?.(error);
|
|
326
434
|
throw error;
|
|
327
435
|
}
|
|
328
|
-
|
|
436
|
+
if (await this._handleElicitationResponse(parsedMessage)) {
|
|
437
|
+
return null;
|
|
438
|
+
}
|
|
439
|
+
this._transport?.onmessage?.(parsedMessage);
|
|
329
440
|
return null;
|
|
330
441
|
} catch (error) {
|
|
331
442
|
console.error("Error forwarding message to SSE:", error);
|
|
332
|
-
|
|
443
|
+
this._transport?.onerror?.(error);
|
|
333
444
|
return error;
|
|
334
445
|
}
|
|
335
446
|
}
|
|
336
447
|
// Delegate all websocket events to the underlying agent
|
|
337
448
|
async webSocketMessage(ws, event) {
|
|
338
|
-
if (
|
|
339
|
-
await
|
|
449
|
+
if (this._status !== "started") {
|
|
450
|
+
await this._initialize();
|
|
340
451
|
}
|
|
341
|
-
return await
|
|
452
|
+
return await this._agent.webSocketMessage(ws, event);
|
|
342
453
|
}
|
|
343
454
|
// WebSocket event handlers for hibernation support
|
|
344
455
|
async webSocketError(ws, error) {
|
|
345
|
-
if (
|
|
346
|
-
await
|
|
456
|
+
if (this._status !== "started") {
|
|
457
|
+
await this._initialize();
|
|
347
458
|
}
|
|
348
|
-
return await
|
|
459
|
+
return await this._agent.webSocketError(ws, error);
|
|
349
460
|
}
|
|
350
461
|
async webSocketClose(ws, code, reason, wasClean) {
|
|
351
|
-
if (
|
|
352
|
-
await
|
|
462
|
+
if (this._status !== "started") {
|
|
463
|
+
await this._initialize();
|
|
353
464
|
}
|
|
354
|
-
return await
|
|
465
|
+
return await this._agent.webSocketClose(ws, code, reason, wasClean);
|
|
355
466
|
}
|
|
356
467
|
static mount(path, {
|
|
357
468
|
binding = "MCP_OBJECT",
|
|
@@ -381,7 +492,7 @@ var _McpAgent = class _McpAgent extends DurableObject {
|
|
|
381
492
|
);
|
|
382
493
|
return new Response("Invalid binding", { status: 500 });
|
|
383
494
|
}
|
|
384
|
-
if (bindingValue
|
|
495
|
+
if (!isDurableObjectNamespace(bindingValue)) {
|
|
385
496
|
return new Response("Invalid binding", { status: 500 });
|
|
386
497
|
}
|
|
387
498
|
const namespace = bindingValue;
|
|
@@ -401,12 +512,26 @@ data: ${relativeUrlWithSession}
|
|
|
401
512
|
writer.write(encoder.encode(endpointMessage));
|
|
402
513
|
const id = namespace.idFromName(`sse:${sessionId}`);
|
|
403
514
|
const doStub = namespace.get(id);
|
|
404
|
-
|
|
515
|
+
try {
|
|
516
|
+
await doStub._init(ctx.props);
|
|
517
|
+
} catch (error) {
|
|
518
|
+
console.error("Failed to initialize McpAgent:", error);
|
|
519
|
+
await writer.close();
|
|
520
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
521
|
+
return new Response(`Initialization failed: ${errorMessage}`, {
|
|
522
|
+
status: 500
|
|
523
|
+
});
|
|
524
|
+
}
|
|
405
525
|
const upgradeUrl = new URL(request.url);
|
|
406
526
|
upgradeUrl.pathname = "/sse";
|
|
527
|
+
const existingHeaders = {};
|
|
528
|
+
request.headers.forEach((value, key) => {
|
|
529
|
+
existingHeaders[key] = value;
|
|
530
|
+
});
|
|
407
531
|
const response = await doStub.fetch(
|
|
408
532
|
new Request(upgradeUrl, {
|
|
409
533
|
headers: {
|
|
534
|
+
...existingHeaders,
|
|
410
535
|
Upgrade: "websocket",
|
|
411
536
|
// Required by PartyServer
|
|
412
537
|
"x-partykit-room": sessionId
|
|
@@ -442,10 +567,10 @@ data: ${JSON.stringify(result.data)}
|
|
|
442
567
|
onMessage(event).catch(console.error);
|
|
443
568
|
});
|
|
444
569
|
ws.addEventListener("error", (error) => {
|
|
445
|
-
async function onError(
|
|
570
|
+
async function onError(_error) {
|
|
446
571
|
try {
|
|
447
572
|
await writer.close();
|
|
448
|
-
} catch (
|
|
573
|
+
} catch (_e) {
|
|
449
574
|
}
|
|
450
575
|
}
|
|
451
576
|
onError(error).catch(console.error);
|
|
@@ -462,9 +587,9 @@ data: ${JSON.stringify(result.data)}
|
|
|
462
587
|
});
|
|
463
588
|
return new Response(readable, {
|
|
464
589
|
headers: {
|
|
465
|
-
"Content-Type": "text/event-stream",
|
|
466
590
|
"Cache-Control": "no-cache",
|
|
467
591
|
Connection: "keep-alive",
|
|
592
|
+
"Content-Type": "text/event-stream",
|
|
468
593
|
...corsHeaders(request, corsOptions)
|
|
469
594
|
}
|
|
470
595
|
});
|
|
@@ -497,26 +622,28 @@ data: ${JSON.stringify(result.data)}
|
|
|
497
622
|
}
|
|
498
623
|
const id = namespace.idFromName(`sse:${sessionId}`);
|
|
499
624
|
const doStub = namespace.get(id);
|
|
500
|
-
const
|
|
625
|
+
const messageBody = await request.json();
|
|
626
|
+
await doStub.updateProps(ctx.props);
|
|
627
|
+
const error = await doStub.onSSEMcpMessage(sessionId, messageBody);
|
|
501
628
|
if (error) {
|
|
502
629
|
return new Response(error.message, {
|
|
503
|
-
status: 400,
|
|
504
630
|
headers: {
|
|
505
|
-
"Content-Type": "text/event-stream",
|
|
506
631
|
"Cache-Control": "no-cache",
|
|
507
632
|
Connection: "keep-alive",
|
|
633
|
+
"Content-Type": "text/event-stream",
|
|
508
634
|
...corsHeaders(request, corsOptions)
|
|
509
|
-
}
|
|
635
|
+
},
|
|
636
|
+
status: 400
|
|
510
637
|
});
|
|
511
638
|
}
|
|
512
639
|
return new Response("Accepted", {
|
|
513
|
-
status: 202,
|
|
514
640
|
headers: {
|
|
515
|
-
"Content-Type": "text/event-stream",
|
|
516
641
|
"Cache-Control": "no-cache",
|
|
517
642
|
Connection: "keep-alive",
|
|
643
|
+
"Content-Type": "text/event-stream",
|
|
518
644
|
...corsHeaders(request, corsOptions)
|
|
519
|
-
}
|
|
645
|
+
},
|
|
646
|
+
status: 202
|
|
520
647
|
});
|
|
521
648
|
}
|
|
522
649
|
return new Response("Not Found", { status: 404 });
|
|
@@ -546,7 +673,7 @@ data: ${JSON.stringify(result.data)}
|
|
|
546
673
|
);
|
|
547
674
|
return new Response("Invalid binding", { status: 500 });
|
|
548
675
|
}
|
|
549
|
-
if (bindingValue
|
|
676
|
+
if (!isDurableObjectNamespace(bindingValue)) {
|
|
550
677
|
return new Response("Invalid binding", { status: 500 });
|
|
551
678
|
}
|
|
552
679
|
const namespace = bindingValue;
|
|
@@ -554,24 +681,24 @@ data: ${JSON.stringify(result.data)}
|
|
|
554
681
|
const acceptHeader = request.headers.get("accept");
|
|
555
682
|
if (!acceptHeader?.includes("application/json") || !acceptHeader.includes("text/event-stream")) {
|
|
556
683
|
const body2 = JSON.stringify({
|
|
557
|
-
jsonrpc: "2.0",
|
|
558
684
|
error: {
|
|
559
685
|
code: -32e3,
|
|
560
686
|
message: "Not Acceptable: Client must accept both application/json and text/event-stream"
|
|
561
687
|
},
|
|
562
|
-
id: null
|
|
688
|
+
id: null,
|
|
689
|
+
jsonrpc: "2.0"
|
|
563
690
|
});
|
|
564
691
|
return new Response(body2, { status: 406 });
|
|
565
692
|
}
|
|
566
693
|
const ct = request.headers.get("content-type");
|
|
567
694
|
if (!ct || !ct.includes("application/json")) {
|
|
568
695
|
const body2 = JSON.stringify({
|
|
569
|
-
jsonrpc: "2.0",
|
|
570
696
|
error: {
|
|
571
697
|
code: -32e3,
|
|
572
698
|
message: "Unsupported Media Type: Content-Type must be application/json"
|
|
573
699
|
},
|
|
574
|
-
id: null
|
|
700
|
+
id: null,
|
|
701
|
+
jsonrpc: "2.0"
|
|
575
702
|
});
|
|
576
703
|
return new Response(body2, { status: 415 });
|
|
577
704
|
}
|
|
@@ -581,12 +708,12 @@ data: ${JSON.stringify(result.data)}
|
|
|
581
708
|
);
|
|
582
709
|
if (contentLength > MAXIMUM_MESSAGE_SIZE_BYTES) {
|
|
583
710
|
const body2 = JSON.stringify({
|
|
584
|
-
jsonrpc: "2.0",
|
|
585
711
|
error: {
|
|
586
712
|
code: -32e3,
|
|
587
713
|
message: `Request body too large. Maximum size is ${MAXIMUM_MESSAGE_SIZE_BYTES} bytes`
|
|
588
714
|
},
|
|
589
|
-
id: null
|
|
715
|
+
id: null,
|
|
716
|
+
jsonrpc: "2.0"
|
|
590
717
|
});
|
|
591
718
|
return new Response(body2, { status: 413 });
|
|
592
719
|
}
|
|
@@ -594,14 +721,14 @@ data: ${JSON.stringify(result.data)}
|
|
|
594
721
|
let rawMessage;
|
|
595
722
|
try {
|
|
596
723
|
rawMessage = await request.json();
|
|
597
|
-
} catch (
|
|
724
|
+
} catch (_error) {
|
|
598
725
|
const body2 = JSON.stringify({
|
|
599
|
-
jsonrpc: "2.0",
|
|
600
726
|
error: {
|
|
601
727
|
code: -32700,
|
|
602
728
|
message: "Parse error: Invalid JSON"
|
|
603
729
|
},
|
|
604
|
-
id: null
|
|
730
|
+
id: null,
|
|
731
|
+
jsonrpc: "2.0"
|
|
605
732
|
});
|
|
606
733
|
return new Response(body2, { status: 400 });
|
|
607
734
|
}
|
|
@@ -615,12 +742,12 @@ data: ${JSON.stringify(result.data)}
|
|
|
615
742
|
for (const msg of arrayMessage) {
|
|
616
743
|
if (!JSONRPCMessageSchema.safeParse(msg).success) {
|
|
617
744
|
const body2 = JSON.stringify({
|
|
618
|
-
jsonrpc: "2.0",
|
|
619
745
|
error: {
|
|
620
746
|
code: -32700,
|
|
621
747
|
message: "Parse error: Invalid JSON-RPC message"
|
|
622
748
|
},
|
|
623
|
-
id: null
|
|
749
|
+
id: null,
|
|
750
|
+
jsonrpc: "2.0"
|
|
624
751
|
});
|
|
625
752
|
return new Response(body2, { status: 400 });
|
|
626
753
|
}
|
|
@@ -631,34 +758,34 @@ data: ${JSON.stringify(result.data)}
|
|
|
631
758
|
);
|
|
632
759
|
if (isInitializationRequest && sessionId) {
|
|
633
760
|
const body2 = JSON.stringify({
|
|
634
|
-
jsonrpc: "2.0",
|
|
635
761
|
error: {
|
|
636
762
|
code: -32600,
|
|
637
763
|
message: "Invalid Request: Initialization requests must not include a sessionId"
|
|
638
764
|
},
|
|
639
|
-
id: null
|
|
765
|
+
id: null,
|
|
766
|
+
jsonrpc: "2.0"
|
|
640
767
|
});
|
|
641
768
|
return new Response(body2, { status: 400 });
|
|
642
769
|
}
|
|
643
770
|
if (isInitializationRequest && messages.length > 1) {
|
|
644
771
|
const body2 = JSON.stringify({
|
|
645
|
-
jsonrpc: "2.0",
|
|
646
772
|
error: {
|
|
647
773
|
code: -32600,
|
|
648
774
|
message: "Invalid Request: Only one initialization request is allowed"
|
|
649
775
|
},
|
|
650
|
-
id: null
|
|
776
|
+
id: null,
|
|
777
|
+
jsonrpc: "2.0"
|
|
651
778
|
});
|
|
652
779
|
return new Response(body2, { status: 400 });
|
|
653
780
|
}
|
|
654
781
|
if (!isInitializationRequest && !sessionId) {
|
|
655
782
|
const body2 = JSON.stringify({
|
|
656
|
-
jsonrpc: "2.0",
|
|
657
783
|
error: {
|
|
658
784
|
code: -32e3,
|
|
659
785
|
message: "Bad Request: Mcp-Session-Id header is required"
|
|
660
786
|
},
|
|
661
|
-
id: null
|
|
787
|
+
id: null,
|
|
788
|
+
jsonrpc: "2.0"
|
|
662
789
|
});
|
|
663
790
|
return new Response(body2, { status: 400 });
|
|
664
791
|
}
|
|
@@ -667,27 +794,48 @@ data: ${JSON.stringify(result.data)}
|
|
|
667
794
|
const doStub = namespace.get(id);
|
|
668
795
|
const isInitialized = await doStub.isInitialized();
|
|
669
796
|
if (isInitializationRequest) {
|
|
670
|
-
|
|
671
|
-
|
|
797
|
+
try {
|
|
798
|
+
await doStub._init(ctx.props);
|
|
799
|
+
await doStub.setInitialized();
|
|
800
|
+
} catch (error) {
|
|
801
|
+
console.error("Failed to initialize McpAgent:", error);
|
|
802
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
803
|
+
const body2 = JSON.stringify({
|
|
804
|
+
error: {
|
|
805
|
+
code: -32001,
|
|
806
|
+
message: `Initialization failed: ${errorMessage}`
|
|
807
|
+
},
|
|
808
|
+
id: null,
|
|
809
|
+
jsonrpc: "2.0"
|
|
810
|
+
});
|
|
811
|
+
return new Response(body2, { status: 500 });
|
|
812
|
+
}
|
|
672
813
|
} else if (!isInitialized) {
|
|
673
814
|
const body2 = JSON.stringify({
|
|
674
|
-
jsonrpc: "2.0",
|
|
675
815
|
error: {
|
|
676
816
|
code: -32001,
|
|
677
817
|
message: "Session not found"
|
|
678
818
|
},
|
|
679
|
-
id: null
|
|
819
|
+
id: null,
|
|
820
|
+
jsonrpc: "2.0"
|
|
680
821
|
});
|
|
681
822
|
return new Response(body2, { status: 404 });
|
|
823
|
+
} else {
|
|
824
|
+
await doStub.updateProps(ctx.props);
|
|
682
825
|
}
|
|
683
826
|
const { readable, writable } = new TransformStream();
|
|
684
827
|
const writer = writable.getWriter();
|
|
685
828
|
const encoder = new TextEncoder();
|
|
686
829
|
const upgradeUrl = new URL(request.url);
|
|
687
830
|
upgradeUrl.pathname = "/streamable-http";
|
|
831
|
+
const existingHeaders = {};
|
|
832
|
+
request.headers.forEach((value, key) => {
|
|
833
|
+
existingHeaders[key] = value;
|
|
834
|
+
});
|
|
688
835
|
const response = await doStub.fetch(
|
|
689
836
|
new Request(upgradeUrl, {
|
|
690
837
|
headers: {
|
|
838
|
+
...existingHeaders,
|
|
691
839
|
Upgrade: "websocket",
|
|
692
840
|
// Required by PartyServer
|
|
693
841
|
"x-partykit-room": sessionId
|
|
@@ -699,12 +847,12 @@ data: ${JSON.stringify(result.data)}
|
|
|
699
847
|
console.error("Failed to establish WebSocket connection");
|
|
700
848
|
await writer.close();
|
|
701
849
|
const body2 = JSON.stringify({
|
|
702
|
-
jsonrpc: "2.0",
|
|
703
850
|
error: {
|
|
704
851
|
code: -32001,
|
|
705
852
|
message: "Failed to establish WebSocket connection"
|
|
706
853
|
},
|
|
707
|
-
id: null
|
|
854
|
+
id: null,
|
|
855
|
+
jsonrpc: "2.0"
|
|
708
856
|
});
|
|
709
857
|
return new Response(body2, { status: 500 });
|
|
710
858
|
}
|
|
@@ -737,10 +885,10 @@ data: ${JSON.stringify(result.data)}
|
|
|
737
885
|
onMessage(event).catch(console.error);
|
|
738
886
|
});
|
|
739
887
|
ws.addEventListener("error", (error) => {
|
|
740
|
-
async function onError(
|
|
888
|
+
async function onError(_error) {
|
|
741
889
|
try {
|
|
742
890
|
await writer.close();
|
|
743
|
-
} catch (
|
|
891
|
+
} catch (_e) {
|
|
744
892
|
}
|
|
745
893
|
}
|
|
746
894
|
onError(error).catch(console.error);
|
|
@@ -764,8 +912,8 @@ data: ${JSON.stringify(result.data)}
|
|
|
764
912
|
}
|
|
765
913
|
ws.close();
|
|
766
914
|
return new Response(null, {
|
|
767
|
-
|
|
768
|
-
|
|
915
|
+
headers: corsHeaders(request, corsOptions),
|
|
916
|
+
status: 202
|
|
769
917
|
});
|
|
770
918
|
}
|
|
771
919
|
for (const message of messages) {
|
|
@@ -776,9 +924,9 @@ data: ${JSON.stringify(result.data)}
|
|
|
776
924
|
}
|
|
777
925
|
return new Response(readable, {
|
|
778
926
|
headers: {
|
|
779
|
-
"Content-Type": "text/event-stream",
|
|
780
927
|
"Cache-Control": "no-cache",
|
|
781
928
|
Connection: "keep-alive",
|
|
929
|
+
"Content-Type": "text/event-stream",
|
|
782
930
|
"mcp-session-id": sessionId,
|
|
783
931
|
...corsHeaders(request, corsOptions)
|
|
784
932
|
},
|
|
@@ -786,33 +934,22 @@ data: ${JSON.stringify(result.data)}
|
|
|
786
934
|
});
|
|
787
935
|
}
|
|
788
936
|
const body = JSON.stringify({
|
|
789
|
-
jsonrpc: "2.0",
|
|
790
937
|
error: {
|
|
791
938
|
code: -32e3,
|
|
792
939
|
message: "Method not allowed"
|
|
793
940
|
},
|
|
794
|
-
id: null
|
|
941
|
+
id: null,
|
|
942
|
+
jsonrpc: "2.0"
|
|
795
943
|
});
|
|
796
944
|
return new Response(body, { status: 405 });
|
|
797
945
|
}
|
|
798
946
|
};
|
|
799
947
|
}
|
|
800
948
|
};
|
|
801
|
-
_status = new WeakMap();
|
|
802
|
-
_transport = new WeakMap();
|
|
803
|
-
_transportType = new WeakMap();
|
|
804
|
-
_requestIdToConnectionId = new WeakMap();
|
|
805
|
-
_agent = new WeakMap();
|
|
806
|
-
_McpAgent_instances = new WeakSet();
|
|
807
|
-
initialize_fn = async function() {
|
|
808
|
-
await this.ctx.blockConcurrencyWhile(async () => {
|
|
809
|
-
__privateSet(this, _status, "starting");
|
|
810
|
-
await this.onStart();
|
|
811
|
-
__privateSet(this, _status, "started");
|
|
812
|
-
});
|
|
813
|
-
};
|
|
814
|
-
var McpAgent = _McpAgent;
|
|
815
949
|
export {
|
|
816
|
-
|
|
950
|
+
ElicitRequestSchema,
|
|
951
|
+
McpAgent,
|
|
952
|
+
SSEEdgeClientTransport,
|
|
953
|
+
StreamableHTTPEdgeClientTransport
|
|
817
954
|
};
|
|
818
955
|
//# sourceMappingURL=index.js.map
|