agents 0.0.0-ad0054b → 0.0.0-b123357
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 -115
- package/dist/ai-chat-agent.js.map +1 -1
- package/dist/ai-react.d.ts +20 -5
- package/dist/ai-react.js +28 -29
- package/dist/ai-react.js.map +1 -1
- package/dist/{chunk-Q5ZBHY4Z.js → chunk-HY7ZLHJB.js} +193 -51
- package/dist/chunk-HY7ZLHJB.js.map +1 -0
- package/dist/chunk-KUH345EY.js +116 -0
- package/dist/chunk-KUH345EY.js.map +1 -0
- package/dist/chunk-OJFA7RKX.js +1270 -0
- package/dist/chunk-OJFA7RKX.js.map +1 -0
- package/dist/chunk-PVQZBKN7.js +106 -0
- package/dist/chunk-PVQZBKN7.js.map +1 -0
- package/dist/client-DgyzBU_8.d.ts +4601 -0
- package/dist/client.d.ts +16 -2
- package/dist/client.js +6 -126
- package/dist/client.js.map +1 -1
- package/dist/index-BCJclX6q.d.ts +615 -0
- package/dist/index.d.ts +35 -308
- package/dist/index.js +10 -3
- package/dist/mcp/client.d.ts +9 -775
- 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 +3 -103
- package/dist/mcp/do-oauth-client-provider.js.map +1 -1
- package/dist/mcp/index.d.ts +41 -14
- package/dist/mcp/index.js +278 -178
- 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 -68
- package/src/index.ts +1093 -140
- package/dist/chunk-A65CRW2D.js +0 -609
- package/dist/chunk-A65CRW2D.js.map +0 -1
- package/dist/chunk-HMLY7DHA.js +0 -16
- package/dist/chunk-Q5ZBHY4Z.js.map +0 -1
- /package/dist/{chunk-HMLY7DHA.js.map → observability/index.js.map} +0 -0
package/dist/mcp/index.js
CHANGED
|
@@ -1,56 +1,62 @@
|
|
|
1
1
|
import {
|
|
2
2
|
Agent
|
|
3
|
-
} from "../chunk-
|
|
4
|
-
import "../chunk-Q5ZBHY4Z.js";
|
|
3
|
+
} from "../chunk-OJFA7RKX.js";
|
|
5
4
|
import {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
5
|
+
SSEEdgeClientTransport,
|
|
6
|
+
StreamableHTTPEdgeClientTransport
|
|
7
|
+
} from "../chunk-HY7ZLHJB.js";
|
|
8
|
+
import "../chunk-PVQZBKN7.js";
|
|
9
|
+
import "../chunk-KUH345EY.js";
|
|
11
10
|
|
|
12
11
|
// src/mcp/index.ts
|
|
13
12
|
import { DurableObject } from "cloudflare:workers";
|
|
14
13
|
import {
|
|
15
14
|
InitializeRequestSchema,
|
|
15
|
+
JSONRPCMessageSchema,
|
|
16
16
|
isJSONRPCError,
|
|
17
17
|
isJSONRPCNotification,
|
|
18
18
|
isJSONRPCRequest,
|
|
19
|
-
isJSONRPCResponse
|
|
20
|
-
|
|
19
|
+
isJSONRPCResponse
|
|
20
|
+
} from "@modelcontextprotocol/sdk/types.js";
|
|
21
|
+
import {
|
|
22
|
+
ElicitRequestSchema
|
|
21
23
|
} from "@modelcontextprotocol/sdk/types.js";
|
|
22
24
|
var MAXIMUM_MESSAGE_SIZE_BYTES = 4 * 1024 * 1024;
|
|
23
|
-
function
|
|
24
|
-
const origin =
|
|
25
|
-
|
|
26
|
-
"Access-Control-Allow-
|
|
27
|
-
"Access-Control-Allow-Methods": corsOptions
|
|
28
|
-
"Access-Control-Allow-
|
|
29
|
-
"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()
|
|
30
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) {
|
|
31
39
|
if (request.method === "OPTIONS") {
|
|
32
|
-
return new Response(null, { headers: corsHeaders });
|
|
40
|
+
return new Response(null, { headers: corsHeaders(request, corsOptions) });
|
|
33
41
|
}
|
|
34
42
|
return null;
|
|
35
43
|
}
|
|
36
|
-
var _getWebSocket, _started;
|
|
37
44
|
var McpSSETransport = class {
|
|
38
45
|
constructor(getWebSocket) {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
__privateSet(this, _getWebSocket, getWebSocket);
|
|
46
|
+
this._started = false;
|
|
47
|
+
this._getWebSocket = getWebSocket;
|
|
42
48
|
}
|
|
43
49
|
async start() {
|
|
44
|
-
if (
|
|
50
|
+
if (this._started) {
|
|
45
51
|
throw new Error("Transport already started");
|
|
46
52
|
}
|
|
47
|
-
|
|
53
|
+
this._started = true;
|
|
48
54
|
}
|
|
49
55
|
async send(message) {
|
|
50
|
-
if (!
|
|
56
|
+
if (!this._started) {
|
|
51
57
|
throw new Error("Transport not started");
|
|
52
58
|
}
|
|
53
|
-
const websocket =
|
|
59
|
+
const websocket = this._getWebSocket();
|
|
54
60
|
if (!websocket) {
|
|
55
61
|
throw new Error("WebSocket not connected");
|
|
56
62
|
}
|
|
@@ -65,52 +71,40 @@ var McpSSETransport = class {
|
|
|
65
71
|
this.onclose?.();
|
|
66
72
|
}
|
|
67
73
|
};
|
|
68
|
-
_getWebSocket = new WeakMap();
|
|
69
|
-
_started = new WeakMap();
|
|
70
|
-
var _getWebSocketForGetRequest, _getWebSocketForMessageID, _notifyResponseIdSent, _started2;
|
|
71
74
|
var McpStreamableHttpTransport = class {
|
|
72
75
|
constructor(getWebSocketForMessageID, notifyResponseIdSent) {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
__privateAdd(this, _getWebSocketForMessageID);
|
|
78
|
-
// Notify the server that a response has been sent for a given message id
|
|
79
|
-
// so that it may clean up it's mapping of message ids to connections
|
|
80
|
-
// once they are no longer needed
|
|
81
|
-
__privateAdd(this, _notifyResponseIdSent);
|
|
82
|
-
__privateAdd(this, _started2, false);
|
|
83
|
-
__privateSet(this, _getWebSocketForMessageID, getWebSocketForMessageID);
|
|
84
|
-
__privateSet(this, _notifyResponseIdSent, notifyResponseIdSent);
|
|
85
|
-
__privateSet(this, _getWebSocketForGetRequest, () => null);
|
|
76
|
+
this._started = false;
|
|
77
|
+
this._getWebSocketForMessageID = getWebSocketForMessageID;
|
|
78
|
+
this._notifyResponseIdSent = notifyResponseIdSent;
|
|
79
|
+
this._getWebSocketForGetRequest = () => null;
|
|
86
80
|
}
|
|
87
81
|
async start() {
|
|
88
|
-
if (
|
|
82
|
+
if (this._started) {
|
|
89
83
|
throw new Error("Transport already started");
|
|
90
84
|
}
|
|
91
|
-
|
|
85
|
+
this._started = true;
|
|
92
86
|
}
|
|
93
87
|
async send(message) {
|
|
94
|
-
if (!
|
|
88
|
+
if (!this._started) {
|
|
95
89
|
throw new Error("Transport not started");
|
|
96
90
|
}
|
|
97
91
|
let websocket = null;
|
|
98
92
|
if (isJSONRPCResponse(message) || isJSONRPCError(message)) {
|
|
99
|
-
websocket =
|
|
93
|
+
websocket = this._getWebSocketForMessageID(message.id.toString());
|
|
100
94
|
if (!websocket) {
|
|
101
95
|
throw new Error(
|
|
102
96
|
`Could not find WebSocket for message id: ${message.id}`
|
|
103
97
|
);
|
|
104
98
|
}
|
|
105
99
|
} else if (isJSONRPCRequest(message)) {
|
|
106
|
-
websocket =
|
|
100
|
+
websocket = this._getWebSocketForGetRequest();
|
|
107
101
|
} else if (isJSONRPCNotification(message)) {
|
|
108
102
|
websocket = null;
|
|
109
103
|
}
|
|
110
104
|
try {
|
|
111
105
|
websocket?.send(JSON.stringify(message));
|
|
112
106
|
if (isJSONRPCResponse(message)) {
|
|
113
|
-
|
|
107
|
+
this._notifyResponseIdSent(message.id.toString());
|
|
114
108
|
}
|
|
115
109
|
} catch (error) {
|
|
116
110
|
this.onerror?.(error);
|
|
@@ -121,28 +115,16 @@ var McpStreamableHttpTransport = class {
|
|
|
121
115
|
this.onclose?.();
|
|
122
116
|
}
|
|
123
117
|
};
|
|
124
|
-
|
|
125
|
-
_getWebSocketForMessageID = new WeakMap();
|
|
126
|
-
_notifyResponseIdSent = new WeakMap();
|
|
127
|
-
_started2 = new WeakMap();
|
|
128
|
-
var _status, _transport, _transportType, _requestIdToConnectionId, _agent, _McpAgent_instances, initialize_fn;
|
|
129
|
-
var _McpAgent = class _McpAgent extends DurableObject {
|
|
118
|
+
var McpAgent = class _McpAgent extends DurableObject {
|
|
130
119
|
constructor(ctx, env) {
|
|
131
120
|
var _a;
|
|
132
121
|
super(ctx, env);
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
__privateAdd(this, _transportType, "unset");
|
|
137
|
-
__privateAdd(this, _requestIdToConnectionId, /* @__PURE__ */ new Map());
|
|
138
|
-
/**
|
|
139
|
-
* Since McpAgent's _aren't_ yet real "Agents", let's only expose a couple of the methods
|
|
140
|
-
* to the outer class: initialState/state/setState/onStateUpdate/sql
|
|
141
|
-
*/
|
|
142
|
-
__privateAdd(this, _agent);
|
|
122
|
+
this._status = "zero";
|
|
123
|
+
this._transportType = "unset";
|
|
124
|
+
this._requestIdToConnectionId = /* @__PURE__ */ new Map();
|
|
143
125
|
this.initRun = false;
|
|
144
126
|
const self = this;
|
|
145
|
-
|
|
127
|
+
this._agent = new (_a = class extends Agent {
|
|
146
128
|
onStateUpdate(state, source) {
|
|
147
129
|
return self.onStateUpdate(state, source);
|
|
148
130
|
}
|
|
@@ -151,26 +133,66 @@ var _McpAgent = class _McpAgent extends DurableObject {
|
|
|
151
133
|
}
|
|
152
134
|
}, _a.options = {
|
|
153
135
|
hibernate: true
|
|
154
|
-
}, _a)(ctx, env)
|
|
136
|
+
}, _a)(ctx, env);
|
|
155
137
|
}
|
|
156
138
|
get mcp() {
|
|
157
|
-
return
|
|
139
|
+
return this._agent.mcp;
|
|
158
140
|
}
|
|
159
141
|
get state() {
|
|
160
|
-
return
|
|
142
|
+
return this._agent.state;
|
|
161
143
|
}
|
|
162
144
|
sql(strings, ...values) {
|
|
163
|
-
return
|
|
145
|
+
return this._agent.sql(strings, ...values);
|
|
164
146
|
}
|
|
165
147
|
setState(state) {
|
|
166
|
-
return
|
|
148
|
+
return this._agent.setState(state);
|
|
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);
|
|
167
187
|
}
|
|
188
|
+
// we leave the variables as unused for autocomplete purposes
|
|
189
|
+
// biome-ignore lint/correctness/noUnusedFunctionParameters: overriden later
|
|
168
190
|
onStateUpdate(state, source) {
|
|
169
191
|
}
|
|
170
192
|
async onStart() {
|
|
171
193
|
var _a;
|
|
172
194
|
const self = this;
|
|
173
|
-
|
|
195
|
+
this._agent = new (_a = class extends Agent {
|
|
174
196
|
constructor() {
|
|
175
197
|
super(...arguments);
|
|
176
198
|
this.initialState = self.initialState;
|
|
@@ -183,22 +205,22 @@ var _McpAgent = class _McpAgent extends DurableObject {
|
|
|
183
205
|
}
|
|
184
206
|
}, _a.options = {
|
|
185
207
|
hibernate: true
|
|
186
|
-
}, _a)(this.ctx, this.env)
|
|
208
|
+
}, _a)(this.ctx, this.env);
|
|
187
209
|
this.props = await this.ctx.storage.get("props");
|
|
188
|
-
|
|
210
|
+
this._transportType = await this.ctx.storage.get(
|
|
189
211
|
"transportType"
|
|
190
|
-
)
|
|
212
|
+
);
|
|
191
213
|
await this._init(this.props);
|
|
192
214
|
const server = await this.server;
|
|
193
|
-
if (
|
|
194
|
-
|
|
195
|
-
await server.connect(
|
|
196
|
-
} else if (
|
|
197
|
-
|
|
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(
|
|
198
220
|
(id) => this.getWebSocketForResponseID(id),
|
|
199
|
-
(id) =>
|
|
200
|
-
)
|
|
201
|
-
await server.connect(
|
|
221
|
+
(id) => this._requestIdToConnectionId.delete(id)
|
|
222
|
+
);
|
|
223
|
+
await server.connect(this._transport);
|
|
202
224
|
}
|
|
203
225
|
}
|
|
204
226
|
async _init(props) {
|
|
@@ -218,10 +240,17 @@ var _McpAgent = class _McpAgent extends DurableObject {
|
|
|
218
240
|
async isInitialized() {
|
|
219
241
|
return await this.ctx.storage.get("initialized") === true;
|
|
220
242
|
}
|
|
243
|
+
async _initialize() {
|
|
244
|
+
await this.ctx.blockConcurrencyWhile(async () => {
|
|
245
|
+
this._status = "starting";
|
|
246
|
+
await this.onStart();
|
|
247
|
+
this._status = "started";
|
|
248
|
+
});
|
|
249
|
+
}
|
|
221
250
|
// Allow the worker to fetch a websocket connection to the agent
|
|
222
251
|
async fetch(request) {
|
|
223
|
-
if (
|
|
224
|
-
await
|
|
252
|
+
if (this._status !== "started") {
|
|
253
|
+
await this._initialize();
|
|
225
254
|
}
|
|
226
255
|
if (request.headers.get("Upgrade") !== "websocket") {
|
|
227
256
|
return new Response("Expected WebSocket Upgrade request", {
|
|
@@ -238,24 +267,24 @@ var _McpAgent = class _McpAgent extends DurableObject {
|
|
|
238
267
|
return new Response("Websocket already connected", { status: 400 });
|
|
239
268
|
}
|
|
240
269
|
await this.ctx.storage.put("transportType", "sse");
|
|
241
|
-
|
|
242
|
-
if (!
|
|
243
|
-
|
|
244
|
-
await server.connect(
|
|
270
|
+
this._transportType = "sse";
|
|
271
|
+
if (!this._transport) {
|
|
272
|
+
this._transport = new McpSSETransport(() => this.getWebSocket());
|
|
273
|
+
await server.connect(this._transport);
|
|
245
274
|
}
|
|
246
|
-
return
|
|
275
|
+
return this._agent.fetch(request);
|
|
247
276
|
}
|
|
248
277
|
case "/streamable-http": {
|
|
249
|
-
if (!
|
|
250
|
-
|
|
278
|
+
if (!this._transport) {
|
|
279
|
+
this._transport = new McpStreamableHttpTransport(
|
|
251
280
|
(id) => this.getWebSocketForResponseID(id),
|
|
252
|
-
(id) =>
|
|
253
|
-
)
|
|
254
|
-
await server.connect(
|
|
281
|
+
(id) => this._requestIdToConnectionId.delete(id)
|
|
282
|
+
);
|
|
283
|
+
await server.connect(this._transport);
|
|
255
284
|
}
|
|
256
285
|
await this.ctx.storage.put("transportType", "streamable-http");
|
|
257
|
-
|
|
258
|
-
return
|
|
286
|
+
this._transportType = "streamable-http";
|
|
287
|
+
return this._agent.fetch(request);
|
|
259
288
|
}
|
|
260
289
|
default:
|
|
261
290
|
return new Response(
|
|
@@ -274,19 +303,19 @@ var _McpAgent = class _McpAgent extends DurableObject {
|
|
|
274
303
|
return websockets[0];
|
|
275
304
|
}
|
|
276
305
|
getWebSocketForResponseID(id) {
|
|
277
|
-
const connectionId =
|
|
306
|
+
const connectionId = this._requestIdToConnectionId.get(id);
|
|
278
307
|
if (connectionId === void 0) {
|
|
279
308
|
return null;
|
|
280
309
|
}
|
|
281
|
-
return
|
|
310
|
+
return this._agent.getConnection(connectionId) ?? null;
|
|
282
311
|
}
|
|
283
312
|
// All messages received here. This is currently never called
|
|
284
313
|
async onMessage(connection, event) {
|
|
285
|
-
if (
|
|
314
|
+
if (this._transportType !== "streamable-http") {
|
|
286
315
|
const err = new Error(
|
|
287
316
|
"Internal Server Error: Expected streamable-http protocol"
|
|
288
317
|
);
|
|
289
|
-
|
|
318
|
+
this._transport?.onerror?.(err);
|
|
290
319
|
return;
|
|
291
320
|
}
|
|
292
321
|
let message;
|
|
@@ -294,58 +323,125 @@ var _McpAgent = class _McpAgent extends DurableObject {
|
|
|
294
323
|
const data = typeof event === "string" ? event : new TextDecoder().decode(event);
|
|
295
324
|
message = JSONRPCMessageSchema.parse(JSON.parse(data));
|
|
296
325
|
} catch (error) {
|
|
297
|
-
|
|
326
|
+
this._transport?.onerror?.(error);
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
329
|
+
if (await this._handleElicitationResponse(message)) {
|
|
298
330
|
return;
|
|
299
331
|
}
|
|
300
332
|
if (isJSONRPCRequest(message)) {
|
|
301
|
-
|
|
333
|
+
this._requestIdToConnectionId.set(message.id.toString(), connection.id);
|
|
334
|
+
}
|
|
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;
|
|
302
395
|
}
|
|
303
|
-
|
|
396
|
+
return false;
|
|
304
397
|
}
|
|
305
398
|
// All messages received over SSE after the initial connection has been established
|
|
306
399
|
// will be passed here
|
|
307
|
-
async onSSEMcpMessage(
|
|
308
|
-
if (
|
|
309
|
-
await
|
|
400
|
+
async onSSEMcpMessage(_sessionId, messageBody) {
|
|
401
|
+
if (this._status !== "started") {
|
|
402
|
+
await this._initialize();
|
|
310
403
|
}
|
|
311
|
-
if (
|
|
404
|
+
if (this._transportType !== "sse") {
|
|
312
405
|
return new Error("Internal Server Error: Expected SSE protocol");
|
|
313
406
|
}
|
|
314
407
|
try {
|
|
315
|
-
const message = await request.json();
|
|
316
408
|
let parsedMessage;
|
|
317
409
|
try {
|
|
318
|
-
parsedMessage = JSONRPCMessageSchema.parse(
|
|
410
|
+
parsedMessage = JSONRPCMessageSchema.parse(messageBody);
|
|
319
411
|
} catch (error) {
|
|
320
|
-
|
|
412
|
+
this._transport?.onerror?.(error);
|
|
321
413
|
throw error;
|
|
322
414
|
}
|
|
323
|
-
|
|
415
|
+
if (await this._handleElicitationResponse(parsedMessage)) {
|
|
416
|
+
return null;
|
|
417
|
+
}
|
|
418
|
+
this._transport?.onmessage?.(parsedMessage);
|
|
324
419
|
return null;
|
|
325
420
|
} catch (error) {
|
|
326
|
-
|
|
421
|
+
console.error("Error forwarding message to SSE:", error);
|
|
422
|
+
this._transport?.onerror?.(error);
|
|
327
423
|
return error;
|
|
328
424
|
}
|
|
329
425
|
}
|
|
330
426
|
// Delegate all websocket events to the underlying agent
|
|
331
427
|
async webSocketMessage(ws, event) {
|
|
332
|
-
if (
|
|
333
|
-
await
|
|
428
|
+
if (this._status !== "started") {
|
|
429
|
+
await this._initialize();
|
|
334
430
|
}
|
|
335
|
-
return await
|
|
431
|
+
return await this._agent.webSocketMessage(ws, event);
|
|
336
432
|
}
|
|
337
433
|
// WebSocket event handlers for hibernation support
|
|
338
434
|
async webSocketError(ws, error) {
|
|
339
|
-
if (
|
|
340
|
-
await
|
|
435
|
+
if (this._status !== "started") {
|
|
436
|
+
await this._initialize();
|
|
341
437
|
}
|
|
342
|
-
return await
|
|
438
|
+
return await this._agent.webSocketError(ws, error);
|
|
343
439
|
}
|
|
344
440
|
async webSocketClose(ws, code, reason, wasClean) {
|
|
345
|
-
if (
|
|
346
|
-
await
|
|
441
|
+
if (this._status !== "started") {
|
|
442
|
+
await this._initialize();
|
|
347
443
|
}
|
|
348
|
-
return await
|
|
444
|
+
return await this._agent.webSocketClose(ws, code, reason, wasClean);
|
|
349
445
|
}
|
|
350
446
|
static mount(path, {
|
|
351
447
|
binding = "MCP_OBJECT",
|
|
@@ -375,7 +471,7 @@ var _McpAgent = class _McpAgent extends DurableObject {
|
|
|
375
471
|
);
|
|
376
472
|
return new Response("Invalid binding", { status: 500 });
|
|
377
473
|
}
|
|
378
|
-
if (bindingValue
|
|
474
|
+
if (!isDurableObjectNamespace(bindingValue)) {
|
|
379
475
|
return new Response("Invalid binding", { status: 500 });
|
|
380
476
|
}
|
|
381
477
|
const namespace = bindingValue;
|
|
@@ -398,9 +494,14 @@ data: ${relativeUrlWithSession}
|
|
|
398
494
|
await doStub._init(ctx.props);
|
|
399
495
|
const upgradeUrl = new URL(request.url);
|
|
400
496
|
upgradeUrl.pathname = "/sse";
|
|
497
|
+
const existingHeaders = {};
|
|
498
|
+
request.headers.forEach((value, key) => {
|
|
499
|
+
existingHeaders[key] = value;
|
|
500
|
+
});
|
|
401
501
|
const response = await doStub.fetch(
|
|
402
502
|
new Request(upgradeUrl, {
|
|
403
503
|
headers: {
|
|
504
|
+
...existingHeaders,
|
|
404
505
|
Upgrade: "websocket",
|
|
405
506
|
// Required by PartyServer
|
|
406
507
|
"x-partykit-room": sessionId
|
|
@@ -436,10 +537,10 @@ data: ${JSON.stringify(result.data)}
|
|
|
436
537
|
onMessage(event).catch(console.error);
|
|
437
538
|
});
|
|
438
539
|
ws.addEventListener("error", (error) => {
|
|
439
|
-
async function onError(
|
|
540
|
+
async function onError(_error) {
|
|
440
541
|
try {
|
|
441
542
|
await writer.close();
|
|
442
|
-
} catch (
|
|
543
|
+
} catch (_e) {
|
|
443
544
|
}
|
|
444
545
|
}
|
|
445
546
|
onError(error).catch(console.error);
|
|
@@ -456,10 +557,10 @@ data: ${JSON.stringify(result.data)}
|
|
|
456
557
|
});
|
|
457
558
|
return new Response(readable, {
|
|
458
559
|
headers: {
|
|
459
|
-
"Content-Type": "text/event-stream",
|
|
460
560
|
"Cache-Control": "no-cache",
|
|
461
561
|
Connection: "keep-alive",
|
|
462
|
-
"
|
|
562
|
+
"Content-Type": "text/event-stream",
|
|
563
|
+
...corsHeaders(request, corsOptions)
|
|
463
564
|
}
|
|
464
565
|
});
|
|
465
566
|
}
|
|
@@ -491,26 +592,27 @@ data: ${JSON.stringify(result.data)}
|
|
|
491
592
|
}
|
|
492
593
|
const id = namespace.idFromName(`sse:${sessionId}`);
|
|
493
594
|
const doStub = namespace.get(id);
|
|
494
|
-
const
|
|
595
|
+
const messageBody = await request.json();
|
|
596
|
+
const error = await doStub.onSSEMcpMessage(sessionId, messageBody);
|
|
495
597
|
if (error) {
|
|
496
598
|
return new Response(error.message, {
|
|
497
|
-
status: 400,
|
|
498
599
|
headers: {
|
|
499
|
-
"Content-Type": "text/event-stream",
|
|
500
600
|
"Cache-Control": "no-cache",
|
|
501
601
|
Connection: "keep-alive",
|
|
502
|
-
"
|
|
503
|
-
|
|
602
|
+
"Content-Type": "text/event-stream",
|
|
603
|
+
...corsHeaders(request, corsOptions)
|
|
604
|
+
},
|
|
605
|
+
status: 400
|
|
504
606
|
});
|
|
505
607
|
}
|
|
506
608
|
return new Response("Accepted", {
|
|
507
|
-
status: 202,
|
|
508
609
|
headers: {
|
|
509
|
-
"Content-Type": "text/event-stream",
|
|
510
610
|
"Cache-Control": "no-cache",
|
|
511
611
|
Connection: "keep-alive",
|
|
512
|
-
"
|
|
513
|
-
|
|
612
|
+
"Content-Type": "text/event-stream",
|
|
613
|
+
...corsHeaders(request, corsOptions)
|
|
614
|
+
},
|
|
615
|
+
status: 202
|
|
514
616
|
});
|
|
515
617
|
}
|
|
516
618
|
return new Response("Not Found", { status: 404 });
|
|
@@ -540,7 +642,7 @@ data: ${JSON.stringify(result.data)}
|
|
|
540
642
|
);
|
|
541
643
|
return new Response("Invalid binding", { status: 500 });
|
|
542
644
|
}
|
|
543
|
-
if (bindingValue
|
|
645
|
+
if (!isDurableObjectNamespace(bindingValue)) {
|
|
544
646
|
return new Response("Invalid binding", { status: 500 });
|
|
545
647
|
}
|
|
546
648
|
const namespace = bindingValue;
|
|
@@ -548,24 +650,24 @@ data: ${JSON.stringify(result.data)}
|
|
|
548
650
|
const acceptHeader = request.headers.get("accept");
|
|
549
651
|
if (!acceptHeader?.includes("application/json") || !acceptHeader.includes("text/event-stream")) {
|
|
550
652
|
const body2 = JSON.stringify({
|
|
551
|
-
jsonrpc: "2.0",
|
|
552
653
|
error: {
|
|
553
654
|
code: -32e3,
|
|
554
655
|
message: "Not Acceptable: Client must accept both application/json and text/event-stream"
|
|
555
656
|
},
|
|
556
|
-
id: null
|
|
657
|
+
id: null,
|
|
658
|
+
jsonrpc: "2.0"
|
|
557
659
|
});
|
|
558
660
|
return new Response(body2, { status: 406 });
|
|
559
661
|
}
|
|
560
662
|
const ct = request.headers.get("content-type");
|
|
561
663
|
if (!ct || !ct.includes("application/json")) {
|
|
562
664
|
const body2 = JSON.stringify({
|
|
563
|
-
jsonrpc: "2.0",
|
|
564
665
|
error: {
|
|
565
666
|
code: -32e3,
|
|
566
667
|
message: "Unsupported Media Type: Content-Type must be application/json"
|
|
567
668
|
},
|
|
568
|
-
id: null
|
|
669
|
+
id: null,
|
|
670
|
+
jsonrpc: "2.0"
|
|
569
671
|
});
|
|
570
672
|
return new Response(body2, { status: 415 });
|
|
571
673
|
}
|
|
@@ -575,12 +677,12 @@ data: ${JSON.stringify(result.data)}
|
|
|
575
677
|
);
|
|
576
678
|
if (contentLength > MAXIMUM_MESSAGE_SIZE_BYTES) {
|
|
577
679
|
const body2 = JSON.stringify({
|
|
578
|
-
jsonrpc: "2.0",
|
|
579
680
|
error: {
|
|
580
681
|
code: -32e3,
|
|
581
682
|
message: `Request body too large. Maximum size is ${MAXIMUM_MESSAGE_SIZE_BYTES} bytes`
|
|
582
683
|
},
|
|
583
|
-
id: null
|
|
684
|
+
id: null,
|
|
685
|
+
jsonrpc: "2.0"
|
|
584
686
|
});
|
|
585
687
|
return new Response(body2, { status: 413 });
|
|
586
688
|
}
|
|
@@ -588,14 +690,14 @@ data: ${JSON.stringify(result.data)}
|
|
|
588
690
|
let rawMessage;
|
|
589
691
|
try {
|
|
590
692
|
rawMessage = await request.json();
|
|
591
|
-
} catch (
|
|
693
|
+
} catch (_error) {
|
|
592
694
|
const body2 = JSON.stringify({
|
|
593
|
-
jsonrpc: "2.0",
|
|
594
695
|
error: {
|
|
595
696
|
code: -32700,
|
|
596
697
|
message: "Parse error: Invalid JSON"
|
|
597
698
|
},
|
|
598
|
-
id: null
|
|
699
|
+
id: null,
|
|
700
|
+
jsonrpc: "2.0"
|
|
599
701
|
});
|
|
600
702
|
return new Response(body2, { status: 400 });
|
|
601
703
|
}
|
|
@@ -609,12 +711,12 @@ data: ${JSON.stringify(result.data)}
|
|
|
609
711
|
for (const msg of arrayMessage) {
|
|
610
712
|
if (!JSONRPCMessageSchema.safeParse(msg).success) {
|
|
611
713
|
const body2 = JSON.stringify({
|
|
612
|
-
jsonrpc: "2.0",
|
|
613
714
|
error: {
|
|
614
715
|
code: -32700,
|
|
615
716
|
message: "Parse error: Invalid JSON-RPC message"
|
|
616
717
|
},
|
|
617
|
-
id: null
|
|
718
|
+
id: null,
|
|
719
|
+
jsonrpc: "2.0"
|
|
618
720
|
});
|
|
619
721
|
return new Response(body2, { status: 400 });
|
|
620
722
|
}
|
|
@@ -625,34 +727,34 @@ data: ${JSON.stringify(result.data)}
|
|
|
625
727
|
);
|
|
626
728
|
if (isInitializationRequest && sessionId) {
|
|
627
729
|
const body2 = JSON.stringify({
|
|
628
|
-
jsonrpc: "2.0",
|
|
629
730
|
error: {
|
|
630
731
|
code: -32600,
|
|
631
732
|
message: "Invalid Request: Initialization requests must not include a sessionId"
|
|
632
733
|
},
|
|
633
|
-
id: null
|
|
734
|
+
id: null,
|
|
735
|
+
jsonrpc: "2.0"
|
|
634
736
|
});
|
|
635
737
|
return new Response(body2, { status: 400 });
|
|
636
738
|
}
|
|
637
739
|
if (isInitializationRequest && messages.length > 1) {
|
|
638
740
|
const body2 = JSON.stringify({
|
|
639
|
-
jsonrpc: "2.0",
|
|
640
741
|
error: {
|
|
641
742
|
code: -32600,
|
|
642
743
|
message: "Invalid Request: Only one initialization request is allowed"
|
|
643
744
|
},
|
|
644
|
-
id: null
|
|
745
|
+
id: null,
|
|
746
|
+
jsonrpc: "2.0"
|
|
645
747
|
});
|
|
646
748
|
return new Response(body2, { status: 400 });
|
|
647
749
|
}
|
|
648
750
|
if (!isInitializationRequest && !sessionId) {
|
|
649
751
|
const body2 = JSON.stringify({
|
|
650
|
-
jsonrpc: "2.0",
|
|
651
752
|
error: {
|
|
652
753
|
code: -32e3,
|
|
653
754
|
message: "Bad Request: Mcp-Session-Id header is required"
|
|
654
755
|
},
|
|
655
|
-
id: null
|
|
756
|
+
id: null,
|
|
757
|
+
jsonrpc: "2.0"
|
|
656
758
|
});
|
|
657
759
|
return new Response(body2, { status: 400 });
|
|
658
760
|
}
|
|
@@ -661,15 +763,16 @@ data: ${JSON.stringify(result.data)}
|
|
|
661
763
|
const doStub = namespace.get(id);
|
|
662
764
|
const isInitialized = await doStub.isInitialized();
|
|
663
765
|
if (isInitializationRequest) {
|
|
766
|
+
await doStub._init(ctx.props);
|
|
664
767
|
await doStub.setInitialized();
|
|
665
768
|
} else if (!isInitialized) {
|
|
666
769
|
const body2 = JSON.stringify({
|
|
667
|
-
jsonrpc: "2.0",
|
|
668
770
|
error: {
|
|
669
771
|
code: -32001,
|
|
670
772
|
message: "Session not found"
|
|
671
773
|
},
|
|
672
|
-
id: null
|
|
774
|
+
id: null,
|
|
775
|
+
jsonrpc: "2.0"
|
|
673
776
|
});
|
|
674
777
|
return new Response(body2, { status: 404 });
|
|
675
778
|
}
|
|
@@ -678,9 +781,14 @@ data: ${JSON.stringify(result.data)}
|
|
|
678
781
|
const encoder = new TextEncoder();
|
|
679
782
|
const upgradeUrl = new URL(request.url);
|
|
680
783
|
upgradeUrl.pathname = "/streamable-http";
|
|
784
|
+
const existingHeaders = {};
|
|
785
|
+
request.headers.forEach((value, key) => {
|
|
786
|
+
existingHeaders[key] = value;
|
|
787
|
+
});
|
|
681
788
|
const response = await doStub.fetch(
|
|
682
789
|
new Request(upgradeUrl, {
|
|
683
790
|
headers: {
|
|
791
|
+
...existingHeaders,
|
|
684
792
|
Upgrade: "websocket",
|
|
685
793
|
// Required by PartyServer
|
|
686
794
|
"x-partykit-room": sessionId
|
|
@@ -692,12 +800,12 @@ data: ${JSON.stringify(result.data)}
|
|
|
692
800
|
console.error("Failed to establish WebSocket connection");
|
|
693
801
|
await writer.close();
|
|
694
802
|
const body2 = JSON.stringify({
|
|
695
|
-
jsonrpc: "2.0",
|
|
696
803
|
error: {
|
|
697
804
|
code: -32001,
|
|
698
805
|
message: "Failed to establish WebSocket connection"
|
|
699
806
|
},
|
|
700
|
-
id: null
|
|
807
|
+
id: null,
|
|
808
|
+
jsonrpc: "2.0"
|
|
701
809
|
});
|
|
702
810
|
return new Response(body2, { status: 500 });
|
|
703
811
|
}
|
|
@@ -730,10 +838,10 @@ data: ${JSON.stringify(result.data)}
|
|
|
730
838
|
onMessage(event).catch(console.error);
|
|
731
839
|
});
|
|
732
840
|
ws.addEventListener("error", (error) => {
|
|
733
|
-
async function onError(
|
|
841
|
+
async function onError(_error) {
|
|
734
842
|
try {
|
|
735
843
|
await writer.close();
|
|
736
|
-
} catch (
|
|
844
|
+
} catch (_e) {
|
|
737
845
|
}
|
|
738
846
|
}
|
|
739
847
|
onError(error).catch(console.error);
|
|
@@ -756,7 +864,10 @@ data: ${JSON.stringify(result.data)}
|
|
|
756
864
|
ws.send(JSON.stringify(message));
|
|
757
865
|
}
|
|
758
866
|
ws.close();
|
|
759
|
-
return new Response(null, {
|
|
867
|
+
return new Response(null, {
|
|
868
|
+
headers: corsHeaders(request, corsOptions),
|
|
869
|
+
status: 202
|
|
870
|
+
});
|
|
760
871
|
}
|
|
761
872
|
for (const message of messages) {
|
|
762
873
|
if (isJSONRPCRequest(message)) {
|
|
@@ -766,43 +877,32 @@ data: ${JSON.stringify(result.data)}
|
|
|
766
877
|
}
|
|
767
878
|
return new Response(readable, {
|
|
768
879
|
headers: {
|
|
769
|
-
"Content-Type": "text/event-stream",
|
|
770
880
|
"Cache-Control": "no-cache",
|
|
771
881
|
Connection: "keep-alive",
|
|
882
|
+
"Content-Type": "text/event-stream",
|
|
772
883
|
"mcp-session-id": sessionId,
|
|
773
|
-
|
|
884
|
+
...corsHeaders(request, corsOptions)
|
|
774
885
|
},
|
|
775
886
|
status: 200
|
|
776
887
|
});
|
|
777
888
|
}
|
|
778
889
|
const body = JSON.stringify({
|
|
779
|
-
jsonrpc: "2.0",
|
|
780
890
|
error: {
|
|
781
891
|
code: -32e3,
|
|
782
892
|
message: "Method not allowed"
|
|
783
893
|
},
|
|
784
|
-
id: null
|
|
894
|
+
id: null,
|
|
895
|
+
jsonrpc: "2.0"
|
|
785
896
|
});
|
|
786
897
|
return new Response(body, { status: 405 });
|
|
787
898
|
}
|
|
788
899
|
};
|
|
789
900
|
}
|
|
790
901
|
};
|
|
791
|
-
_status = new WeakMap();
|
|
792
|
-
_transport = new WeakMap();
|
|
793
|
-
_transportType = new WeakMap();
|
|
794
|
-
_requestIdToConnectionId = new WeakMap();
|
|
795
|
-
_agent = new WeakMap();
|
|
796
|
-
_McpAgent_instances = new WeakSet();
|
|
797
|
-
initialize_fn = async function() {
|
|
798
|
-
await this.ctx.blockConcurrencyWhile(async () => {
|
|
799
|
-
__privateSet(this, _status, "starting");
|
|
800
|
-
await this.onStart();
|
|
801
|
-
__privateSet(this, _status, "started");
|
|
802
|
-
});
|
|
803
|
-
};
|
|
804
|
-
var McpAgent = _McpAgent;
|
|
805
902
|
export {
|
|
806
|
-
|
|
903
|
+
ElicitRequestSchema,
|
|
904
|
+
McpAgent,
|
|
905
|
+
SSEEdgeClientTransport,
|
|
906
|
+
StreamableHTTPEdgeClientTransport
|
|
807
907
|
};
|
|
808
908
|
//# sourceMappingURL=index.js.map
|