agents 0.0.0-e416962 → 0.0.0-e4a2352
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-JXN5WZFQ.js +1287 -0
- package/dist/chunk-JXN5WZFQ.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/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 +42 -14
- package/dist/mcp/index.js +286 -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 -68
- package/src/index.ts +1120 -143
- package/dist/chunk-HMLY7DHA.js +0 -16
- package/dist/chunk-HN5JVKAZ.js +0 -606
- package/dist/chunk-HN5JVKAZ.js.map +0 -1
- 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-JXN5WZFQ.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,30 +205,29 @@ 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) {
|
|
205
|
-
await this.
|
|
227
|
+
await this.updateProps(props);
|
|
206
228
|
if (!this.ctx.storage.get("transportType")) {
|
|
207
229
|
await this.ctx.storage.put("transportType", "unset");
|
|
208
230
|
}
|
|
209
|
-
this.props = props;
|
|
210
231
|
if (!this.initRun) {
|
|
211
232
|
this.initRun = true;
|
|
212
233
|
await this.init();
|
|
@@ -218,10 +239,21 @@ var _McpAgent = class _McpAgent extends DurableObject {
|
|
|
218
239
|
async isInitialized() {
|
|
219
240
|
return await this.ctx.storage.get("initialized") === true;
|
|
220
241
|
}
|
|
242
|
+
async updateProps(props) {
|
|
243
|
+
await this.ctx.storage.put("props", props ?? {});
|
|
244
|
+
this.props = props;
|
|
245
|
+
}
|
|
246
|
+
async _initialize() {
|
|
247
|
+
await this.ctx.blockConcurrencyWhile(async () => {
|
|
248
|
+
this._status = "starting";
|
|
249
|
+
await this.onStart();
|
|
250
|
+
this._status = "started";
|
|
251
|
+
});
|
|
252
|
+
}
|
|
221
253
|
// Allow the worker to fetch a websocket connection to the agent
|
|
222
254
|
async fetch(request) {
|
|
223
|
-
if (
|
|
224
|
-
await
|
|
255
|
+
if (this._status !== "started") {
|
|
256
|
+
await this._initialize();
|
|
225
257
|
}
|
|
226
258
|
if (request.headers.get("Upgrade") !== "websocket") {
|
|
227
259
|
return new Response("Expected WebSocket Upgrade request", {
|
|
@@ -238,24 +270,24 @@ var _McpAgent = class _McpAgent extends DurableObject {
|
|
|
238
270
|
return new Response("Websocket already connected", { status: 400 });
|
|
239
271
|
}
|
|
240
272
|
await this.ctx.storage.put("transportType", "sse");
|
|
241
|
-
|
|
242
|
-
if (!
|
|
243
|
-
|
|
244
|
-
await server.connect(
|
|
273
|
+
this._transportType = "sse";
|
|
274
|
+
if (!this._transport) {
|
|
275
|
+
this._transport = new McpSSETransport(() => this.getWebSocket());
|
|
276
|
+
await server.connect(this._transport);
|
|
245
277
|
}
|
|
246
|
-
return
|
|
278
|
+
return this._agent.fetch(request);
|
|
247
279
|
}
|
|
248
280
|
case "/streamable-http": {
|
|
249
|
-
if (!
|
|
250
|
-
|
|
281
|
+
if (!this._transport) {
|
|
282
|
+
this._transport = new McpStreamableHttpTransport(
|
|
251
283
|
(id) => this.getWebSocketForResponseID(id),
|
|
252
|
-
(id) =>
|
|
253
|
-
)
|
|
254
|
-
await server.connect(
|
|
284
|
+
(id) => this._requestIdToConnectionId.delete(id)
|
|
285
|
+
);
|
|
286
|
+
await server.connect(this._transport);
|
|
255
287
|
}
|
|
256
288
|
await this.ctx.storage.put("transportType", "streamable-http");
|
|
257
|
-
|
|
258
|
-
return
|
|
289
|
+
this._transportType = "streamable-http";
|
|
290
|
+
return this._agent.fetch(request);
|
|
259
291
|
}
|
|
260
292
|
default:
|
|
261
293
|
return new Response(
|
|
@@ -274,19 +306,19 @@ var _McpAgent = class _McpAgent extends DurableObject {
|
|
|
274
306
|
return websockets[0];
|
|
275
307
|
}
|
|
276
308
|
getWebSocketForResponseID(id) {
|
|
277
|
-
const connectionId =
|
|
309
|
+
const connectionId = this._requestIdToConnectionId.get(id);
|
|
278
310
|
if (connectionId === void 0) {
|
|
279
311
|
return null;
|
|
280
312
|
}
|
|
281
|
-
return
|
|
313
|
+
return this._agent.getConnection(connectionId) ?? null;
|
|
282
314
|
}
|
|
283
315
|
// All messages received here. This is currently never called
|
|
284
316
|
async onMessage(connection, event) {
|
|
285
|
-
if (
|
|
317
|
+
if (this._transportType !== "streamable-http") {
|
|
286
318
|
const err = new Error(
|
|
287
319
|
"Internal Server Error: Expected streamable-http protocol"
|
|
288
320
|
);
|
|
289
|
-
|
|
321
|
+
this._transport?.onerror?.(err);
|
|
290
322
|
return;
|
|
291
323
|
}
|
|
292
324
|
let message;
|
|
@@ -294,58 +326,125 @@ var _McpAgent = class _McpAgent extends DurableObject {
|
|
|
294
326
|
const data = typeof event === "string" ? event : new TextDecoder().decode(event);
|
|
295
327
|
message = JSONRPCMessageSchema.parse(JSON.parse(data));
|
|
296
328
|
} catch (error) {
|
|
297
|
-
|
|
329
|
+
this._transport?.onerror?.(error);
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
332
|
+
if (await this._handleElicitationResponse(message)) {
|
|
298
333
|
return;
|
|
299
334
|
}
|
|
300
335
|
if (isJSONRPCRequest(message)) {
|
|
301
|
-
|
|
336
|
+
this._requestIdToConnectionId.set(message.id.toString(), connection.id);
|
|
337
|
+
}
|
|
338
|
+
this._transport?.onmessage?.(message);
|
|
339
|
+
}
|
|
340
|
+
/**
|
|
341
|
+
* Wait for elicitation response through storage polling
|
|
342
|
+
*/
|
|
343
|
+
async _waitForElicitationResponse(requestId) {
|
|
344
|
+
const startTime = Date.now();
|
|
345
|
+
const timeout = 6e4;
|
|
346
|
+
try {
|
|
347
|
+
while (Date.now() - startTime < timeout) {
|
|
348
|
+
const response = await this.ctx.storage.get(
|
|
349
|
+
`elicitation:response:${requestId}`
|
|
350
|
+
);
|
|
351
|
+
if (response) {
|
|
352
|
+
await this.ctx.storage.delete(`elicitation:${requestId}`);
|
|
353
|
+
await this.ctx.storage.delete(`elicitation:response:${requestId}`);
|
|
354
|
+
return response;
|
|
355
|
+
}
|
|
356
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
357
|
+
}
|
|
358
|
+
throw new Error("Elicitation request timed out");
|
|
359
|
+
} finally {
|
|
360
|
+
await this.ctx.storage.delete(`elicitation:${requestId}`);
|
|
361
|
+
await this.ctx.storage.delete(`elicitation:response:${requestId}`);
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
/**
|
|
365
|
+
* Handle elicitation responses */
|
|
366
|
+
async _handleElicitationResponse(message) {
|
|
367
|
+
if (isJSONRPCResponse(message) && message.result) {
|
|
368
|
+
const requestId = message.id?.toString();
|
|
369
|
+
if (!requestId || !requestId.startsWith("elicit_")) return false;
|
|
370
|
+
const pendingRequest = await this.ctx.storage.get(
|
|
371
|
+
`elicitation:${requestId}`
|
|
372
|
+
);
|
|
373
|
+
if (!pendingRequest) return false;
|
|
374
|
+
await this.ctx.storage.put(
|
|
375
|
+
`elicitation:response:${requestId}`,
|
|
376
|
+
message.result
|
|
377
|
+
);
|
|
378
|
+
return true;
|
|
379
|
+
}
|
|
380
|
+
if (isJSONRPCError(message)) {
|
|
381
|
+
const requestId = message.id?.toString();
|
|
382
|
+
if (!requestId || !requestId.startsWith("elicit_")) return false;
|
|
383
|
+
const pendingRequest = await this.ctx.storage.get(
|
|
384
|
+
`elicitation:${requestId}`
|
|
385
|
+
);
|
|
386
|
+
if (!pendingRequest) return false;
|
|
387
|
+
const errorResult = {
|
|
388
|
+
action: "cancel",
|
|
389
|
+
content: {
|
|
390
|
+
error: message.error.message || "Elicitation request failed"
|
|
391
|
+
}
|
|
392
|
+
};
|
|
393
|
+
await this.ctx.storage.put(
|
|
394
|
+
`elicitation:response:${requestId}`,
|
|
395
|
+
errorResult
|
|
396
|
+
);
|
|
397
|
+
return true;
|
|
302
398
|
}
|
|
303
|
-
|
|
399
|
+
return false;
|
|
304
400
|
}
|
|
305
401
|
// All messages received over SSE after the initial connection has been established
|
|
306
402
|
// will be passed here
|
|
307
|
-
async onSSEMcpMessage(
|
|
308
|
-
if (
|
|
309
|
-
await
|
|
403
|
+
async onSSEMcpMessage(_sessionId, messageBody) {
|
|
404
|
+
if (this._status !== "started") {
|
|
405
|
+
await this._initialize();
|
|
310
406
|
}
|
|
311
|
-
if (
|
|
407
|
+
if (this._transportType !== "sse") {
|
|
312
408
|
return new Error("Internal Server Error: Expected SSE protocol");
|
|
313
409
|
}
|
|
314
410
|
try {
|
|
315
|
-
const message = await request.json();
|
|
316
411
|
let parsedMessage;
|
|
317
412
|
try {
|
|
318
|
-
parsedMessage = JSONRPCMessageSchema.parse(
|
|
413
|
+
parsedMessage = JSONRPCMessageSchema.parse(messageBody);
|
|
319
414
|
} catch (error) {
|
|
320
|
-
|
|
415
|
+
this._transport?.onerror?.(error);
|
|
321
416
|
throw error;
|
|
322
417
|
}
|
|
323
|
-
|
|
418
|
+
if (await this._handleElicitationResponse(parsedMessage)) {
|
|
419
|
+
return null;
|
|
420
|
+
}
|
|
421
|
+
this._transport?.onmessage?.(parsedMessage);
|
|
324
422
|
return null;
|
|
325
423
|
} catch (error) {
|
|
326
|
-
|
|
424
|
+
console.error("Error forwarding message to SSE:", error);
|
|
425
|
+
this._transport?.onerror?.(error);
|
|
327
426
|
return error;
|
|
328
427
|
}
|
|
329
428
|
}
|
|
330
429
|
// Delegate all websocket events to the underlying agent
|
|
331
430
|
async webSocketMessage(ws, event) {
|
|
332
|
-
if (
|
|
333
|
-
await
|
|
431
|
+
if (this._status !== "started") {
|
|
432
|
+
await this._initialize();
|
|
334
433
|
}
|
|
335
|
-
return await
|
|
434
|
+
return await this._agent.webSocketMessage(ws, event);
|
|
336
435
|
}
|
|
337
436
|
// WebSocket event handlers for hibernation support
|
|
338
437
|
async webSocketError(ws, error) {
|
|
339
|
-
if (
|
|
340
|
-
await
|
|
438
|
+
if (this._status !== "started") {
|
|
439
|
+
await this._initialize();
|
|
341
440
|
}
|
|
342
|
-
return await
|
|
441
|
+
return await this._agent.webSocketError(ws, error);
|
|
343
442
|
}
|
|
344
443
|
async webSocketClose(ws, code, reason, wasClean) {
|
|
345
|
-
if (
|
|
346
|
-
await
|
|
444
|
+
if (this._status !== "started") {
|
|
445
|
+
await this._initialize();
|
|
347
446
|
}
|
|
348
|
-
return await
|
|
447
|
+
return await this._agent.webSocketClose(ws, code, reason, wasClean);
|
|
349
448
|
}
|
|
350
449
|
static mount(path, {
|
|
351
450
|
binding = "MCP_OBJECT",
|
|
@@ -375,7 +474,7 @@ var _McpAgent = class _McpAgent extends DurableObject {
|
|
|
375
474
|
);
|
|
376
475
|
return new Response("Invalid binding", { status: 500 });
|
|
377
476
|
}
|
|
378
|
-
if (bindingValue
|
|
477
|
+
if (!isDurableObjectNamespace(bindingValue)) {
|
|
379
478
|
return new Response("Invalid binding", { status: 500 });
|
|
380
479
|
}
|
|
381
480
|
const namespace = bindingValue;
|
|
@@ -398,9 +497,14 @@ data: ${relativeUrlWithSession}
|
|
|
398
497
|
await doStub._init(ctx.props);
|
|
399
498
|
const upgradeUrl = new URL(request.url);
|
|
400
499
|
upgradeUrl.pathname = "/sse";
|
|
500
|
+
const existingHeaders = {};
|
|
501
|
+
request.headers.forEach((value, key) => {
|
|
502
|
+
existingHeaders[key] = value;
|
|
503
|
+
});
|
|
401
504
|
const response = await doStub.fetch(
|
|
402
505
|
new Request(upgradeUrl, {
|
|
403
506
|
headers: {
|
|
507
|
+
...existingHeaders,
|
|
404
508
|
Upgrade: "websocket",
|
|
405
509
|
// Required by PartyServer
|
|
406
510
|
"x-partykit-room": sessionId
|
|
@@ -436,10 +540,10 @@ data: ${JSON.stringify(result.data)}
|
|
|
436
540
|
onMessage(event).catch(console.error);
|
|
437
541
|
});
|
|
438
542
|
ws.addEventListener("error", (error) => {
|
|
439
|
-
async function onError(
|
|
543
|
+
async function onError(_error) {
|
|
440
544
|
try {
|
|
441
545
|
await writer.close();
|
|
442
|
-
} catch (
|
|
546
|
+
} catch (_e) {
|
|
443
547
|
}
|
|
444
548
|
}
|
|
445
549
|
onError(error).catch(console.error);
|
|
@@ -456,10 +560,10 @@ data: ${JSON.stringify(result.data)}
|
|
|
456
560
|
});
|
|
457
561
|
return new Response(readable, {
|
|
458
562
|
headers: {
|
|
459
|
-
"Content-Type": "text/event-stream",
|
|
460
563
|
"Cache-Control": "no-cache",
|
|
461
564
|
Connection: "keep-alive",
|
|
462
|
-
"
|
|
565
|
+
"Content-Type": "text/event-stream",
|
|
566
|
+
...corsHeaders(request, corsOptions)
|
|
463
567
|
}
|
|
464
568
|
});
|
|
465
569
|
}
|
|
@@ -491,26 +595,28 @@ data: ${JSON.stringify(result.data)}
|
|
|
491
595
|
}
|
|
492
596
|
const id = namespace.idFromName(`sse:${sessionId}`);
|
|
493
597
|
const doStub = namespace.get(id);
|
|
494
|
-
const
|
|
598
|
+
const messageBody = await request.json();
|
|
599
|
+
await doStub.updateProps(ctx.props);
|
|
600
|
+
const error = await doStub.onSSEMcpMessage(sessionId, messageBody);
|
|
495
601
|
if (error) {
|
|
496
602
|
return new Response(error.message, {
|
|
497
|
-
status: 400,
|
|
498
603
|
headers: {
|
|
499
|
-
"Content-Type": "text/event-stream",
|
|
500
604
|
"Cache-Control": "no-cache",
|
|
501
605
|
Connection: "keep-alive",
|
|
502
|
-
"
|
|
503
|
-
|
|
606
|
+
"Content-Type": "text/event-stream",
|
|
607
|
+
...corsHeaders(request, corsOptions)
|
|
608
|
+
},
|
|
609
|
+
status: 400
|
|
504
610
|
});
|
|
505
611
|
}
|
|
506
612
|
return new Response("Accepted", {
|
|
507
|
-
status: 202,
|
|
508
613
|
headers: {
|
|
509
|
-
"Content-Type": "text/event-stream",
|
|
510
614
|
"Cache-Control": "no-cache",
|
|
511
615
|
Connection: "keep-alive",
|
|
512
|
-
"
|
|
513
|
-
|
|
616
|
+
"Content-Type": "text/event-stream",
|
|
617
|
+
...corsHeaders(request, corsOptions)
|
|
618
|
+
},
|
|
619
|
+
status: 202
|
|
514
620
|
});
|
|
515
621
|
}
|
|
516
622
|
return new Response("Not Found", { status: 404 });
|
|
@@ -540,7 +646,7 @@ data: ${JSON.stringify(result.data)}
|
|
|
540
646
|
);
|
|
541
647
|
return new Response("Invalid binding", { status: 500 });
|
|
542
648
|
}
|
|
543
|
-
if (bindingValue
|
|
649
|
+
if (!isDurableObjectNamespace(bindingValue)) {
|
|
544
650
|
return new Response("Invalid binding", { status: 500 });
|
|
545
651
|
}
|
|
546
652
|
const namespace = bindingValue;
|
|
@@ -548,24 +654,24 @@ data: ${JSON.stringify(result.data)}
|
|
|
548
654
|
const acceptHeader = request.headers.get("accept");
|
|
549
655
|
if (!acceptHeader?.includes("application/json") || !acceptHeader.includes("text/event-stream")) {
|
|
550
656
|
const body2 = JSON.stringify({
|
|
551
|
-
jsonrpc: "2.0",
|
|
552
657
|
error: {
|
|
553
658
|
code: -32e3,
|
|
554
659
|
message: "Not Acceptable: Client must accept both application/json and text/event-stream"
|
|
555
660
|
},
|
|
556
|
-
id: null
|
|
661
|
+
id: null,
|
|
662
|
+
jsonrpc: "2.0"
|
|
557
663
|
});
|
|
558
664
|
return new Response(body2, { status: 406 });
|
|
559
665
|
}
|
|
560
666
|
const ct = request.headers.get("content-type");
|
|
561
667
|
if (!ct || !ct.includes("application/json")) {
|
|
562
668
|
const body2 = JSON.stringify({
|
|
563
|
-
jsonrpc: "2.0",
|
|
564
669
|
error: {
|
|
565
670
|
code: -32e3,
|
|
566
671
|
message: "Unsupported Media Type: Content-Type must be application/json"
|
|
567
672
|
},
|
|
568
|
-
id: null
|
|
673
|
+
id: null,
|
|
674
|
+
jsonrpc: "2.0"
|
|
569
675
|
});
|
|
570
676
|
return new Response(body2, { status: 415 });
|
|
571
677
|
}
|
|
@@ -575,12 +681,12 @@ data: ${JSON.stringify(result.data)}
|
|
|
575
681
|
);
|
|
576
682
|
if (contentLength > MAXIMUM_MESSAGE_SIZE_BYTES) {
|
|
577
683
|
const body2 = JSON.stringify({
|
|
578
|
-
jsonrpc: "2.0",
|
|
579
684
|
error: {
|
|
580
685
|
code: -32e3,
|
|
581
686
|
message: `Request body too large. Maximum size is ${MAXIMUM_MESSAGE_SIZE_BYTES} bytes`
|
|
582
687
|
},
|
|
583
|
-
id: null
|
|
688
|
+
id: null,
|
|
689
|
+
jsonrpc: "2.0"
|
|
584
690
|
});
|
|
585
691
|
return new Response(body2, { status: 413 });
|
|
586
692
|
}
|
|
@@ -588,14 +694,14 @@ data: ${JSON.stringify(result.data)}
|
|
|
588
694
|
let rawMessage;
|
|
589
695
|
try {
|
|
590
696
|
rawMessage = await request.json();
|
|
591
|
-
} catch (
|
|
697
|
+
} catch (_error) {
|
|
592
698
|
const body2 = JSON.stringify({
|
|
593
|
-
jsonrpc: "2.0",
|
|
594
699
|
error: {
|
|
595
700
|
code: -32700,
|
|
596
701
|
message: "Parse error: Invalid JSON"
|
|
597
702
|
},
|
|
598
|
-
id: null
|
|
703
|
+
id: null,
|
|
704
|
+
jsonrpc: "2.0"
|
|
599
705
|
});
|
|
600
706
|
return new Response(body2, { status: 400 });
|
|
601
707
|
}
|
|
@@ -609,12 +715,12 @@ data: ${JSON.stringify(result.data)}
|
|
|
609
715
|
for (const msg of arrayMessage) {
|
|
610
716
|
if (!JSONRPCMessageSchema.safeParse(msg).success) {
|
|
611
717
|
const body2 = JSON.stringify({
|
|
612
|
-
jsonrpc: "2.0",
|
|
613
718
|
error: {
|
|
614
719
|
code: -32700,
|
|
615
720
|
message: "Parse error: Invalid JSON-RPC message"
|
|
616
721
|
},
|
|
617
|
-
id: null
|
|
722
|
+
id: null,
|
|
723
|
+
jsonrpc: "2.0"
|
|
618
724
|
});
|
|
619
725
|
return new Response(body2, { status: 400 });
|
|
620
726
|
}
|
|
@@ -625,34 +731,34 @@ data: ${JSON.stringify(result.data)}
|
|
|
625
731
|
);
|
|
626
732
|
if (isInitializationRequest && sessionId) {
|
|
627
733
|
const body2 = JSON.stringify({
|
|
628
|
-
jsonrpc: "2.0",
|
|
629
734
|
error: {
|
|
630
735
|
code: -32600,
|
|
631
736
|
message: "Invalid Request: Initialization requests must not include a sessionId"
|
|
632
737
|
},
|
|
633
|
-
id: null
|
|
738
|
+
id: null,
|
|
739
|
+
jsonrpc: "2.0"
|
|
634
740
|
});
|
|
635
741
|
return new Response(body2, { status: 400 });
|
|
636
742
|
}
|
|
637
743
|
if (isInitializationRequest && messages.length > 1) {
|
|
638
744
|
const body2 = JSON.stringify({
|
|
639
|
-
jsonrpc: "2.0",
|
|
640
745
|
error: {
|
|
641
746
|
code: -32600,
|
|
642
747
|
message: "Invalid Request: Only one initialization request is allowed"
|
|
643
748
|
},
|
|
644
|
-
id: null
|
|
749
|
+
id: null,
|
|
750
|
+
jsonrpc: "2.0"
|
|
645
751
|
});
|
|
646
752
|
return new Response(body2, { status: 400 });
|
|
647
753
|
}
|
|
648
754
|
if (!isInitializationRequest && !sessionId) {
|
|
649
755
|
const body2 = JSON.stringify({
|
|
650
|
-
jsonrpc: "2.0",
|
|
651
756
|
error: {
|
|
652
757
|
code: -32e3,
|
|
653
758
|
message: "Bad Request: Mcp-Session-Id header is required"
|
|
654
759
|
},
|
|
655
|
-
id: null
|
|
760
|
+
id: null,
|
|
761
|
+
jsonrpc: "2.0"
|
|
656
762
|
});
|
|
657
763
|
return new Response(body2, { status: 400 });
|
|
658
764
|
}
|
|
@@ -661,26 +767,34 @@ data: ${JSON.stringify(result.data)}
|
|
|
661
767
|
const doStub = namespace.get(id);
|
|
662
768
|
const isInitialized = await doStub.isInitialized();
|
|
663
769
|
if (isInitializationRequest) {
|
|
770
|
+
await doStub._init(ctx.props);
|
|
664
771
|
await doStub.setInitialized();
|
|
665
772
|
} else if (!isInitialized) {
|
|
666
773
|
const body2 = JSON.stringify({
|
|
667
|
-
jsonrpc: "2.0",
|
|
668
774
|
error: {
|
|
669
775
|
code: -32001,
|
|
670
776
|
message: "Session not found"
|
|
671
777
|
},
|
|
672
|
-
id: null
|
|
778
|
+
id: null,
|
|
779
|
+
jsonrpc: "2.0"
|
|
673
780
|
});
|
|
674
781
|
return new Response(body2, { status: 404 });
|
|
782
|
+
} else {
|
|
783
|
+
await doStub.updateProps(ctx.props);
|
|
675
784
|
}
|
|
676
785
|
const { readable, writable } = new TransformStream();
|
|
677
786
|
const writer = writable.getWriter();
|
|
678
787
|
const encoder = new TextEncoder();
|
|
679
788
|
const upgradeUrl = new URL(request.url);
|
|
680
789
|
upgradeUrl.pathname = "/streamable-http";
|
|
790
|
+
const existingHeaders = {};
|
|
791
|
+
request.headers.forEach((value, key) => {
|
|
792
|
+
existingHeaders[key] = value;
|
|
793
|
+
});
|
|
681
794
|
const response = await doStub.fetch(
|
|
682
795
|
new Request(upgradeUrl, {
|
|
683
796
|
headers: {
|
|
797
|
+
...existingHeaders,
|
|
684
798
|
Upgrade: "websocket",
|
|
685
799
|
// Required by PartyServer
|
|
686
800
|
"x-partykit-room": sessionId
|
|
@@ -692,12 +806,12 @@ data: ${JSON.stringify(result.data)}
|
|
|
692
806
|
console.error("Failed to establish WebSocket connection");
|
|
693
807
|
await writer.close();
|
|
694
808
|
const body2 = JSON.stringify({
|
|
695
|
-
jsonrpc: "2.0",
|
|
696
809
|
error: {
|
|
697
810
|
code: -32001,
|
|
698
811
|
message: "Failed to establish WebSocket connection"
|
|
699
812
|
},
|
|
700
|
-
id: null
|
|
813
|
+
id: null,
|
|
814
|
+
jsonrpc: "2.0"
|
|
701
815
|
});
|
|
702
816
|
return new Response(body2, { status: 500 });
|
|
703
817
|
}
|
|
@@ -730,10 +844,10 @@ data: ${JSON.stringify(result.data)}
|
|
|
730
844
|
onMessage(event).catch(console.error);
|
|
731
845
|
});
|
|
732
846
|
ws.addEventListener("error", (error) => {
|
|
733
|
-
async function onError(
|
|
847
|
+
async function onError(_error) {
|
|
734
848
|
try {
|
|
735
849
|
await writer.close();
|
|
736
|
-
} catch (
|
|
850
|
+
} catch (_e) {
|
|
737
851
|
}
|
|
738
852
|
}
|
|
739
853
|
onError(error).catch(console.error);
|
|
@@ -756,7 +870,10 @@ data: ${JSON.stringify(result.data)}
|
|
|
756
870
|
ws.send(JSON.stringify(message));
|
|
757
871
|
}
|
|
758
872
|
ws.close();
|
|
759
|
-
return new Response(null, {
|
|
873
|
+
return new Response(null, {
|
|
874
|
+
headers: corsHeaders(request, corsOptions),
|
|
875
|
+
status: 202
|
|
876
|
+
});
|
|
760
877
|
}
|
|
761
878
|
for (const message of messages) {
|
|
762
879
|
if (isJSONRPCRequest(message)) {
|
|
@@ -766,43 +883,32 @@ data: ${JSON.stringify(result.data)}
|
|
|
766
883
|
}
|
|
767
884
|
return new Response(readable, {
|
|
768
885
|
headers: {
|
|
769
|
-
"Content-Type": "text/event-stream",
|
|
770
886
|
"Cache-Control": "no-cache",
|
|
771
887
|
Connection: "keep-alive",
|
|
888
|
+
"Content-Type": "text/event-stream",
|
|
772
889
|
"mcp-session-id": sessionId,
|
|
773
|
-
|
|
890
|
+
...corsHeaders(request, corsOptions)
|
|
774
891
|
},
|
|
775
892
|
status: 200
|
|
776
893
|
});
|
|
777
894
|
}
|
|
778
895
|
const body = JSON.stringify({
|
|
779
|
-
jsonrpc: "2.0",
|
|
780
896
|
error: {
|
|
781
897
|
code: -32e3,
|
|
782
898
|
message: "Method not allowed"
|
|
783
899
|
},
|
|
784
|
-
id: null
|
|
900
|
+
id: null,
|
|
901
|
+
jsonrpc: "2.0"
|
|
785
902
|
});
|
|
786
903
|
return new Response(body, { status: 405 });
|
|
787
904
|
}
|
|
788
905
|
};
|
|
789
906
|
}
|
|
790
907
|
};
|
|
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
908
|
export {
|
|
806
|
-
|
|
909
|
+
ElicitRequestSchema,
|
|
910
|
+
McpAgent,
|
|
911
|
+
SSEEdgeClientTransport,
|
|
912
|
+
StreamableHTTPEdgeClientTransport
|
|
807
913
|
};
|
|
808
914
|
//# sourceMappingURL=index.js.map
|