agents 0.0.0-62d4e85 → 0.0.0-63d8af8

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.
@@ -1,577 +1,94 @@
1
- import {
2
- CallToolResultSchema,
3
- CancelledNotificationSchema,
4
- CompleteResultSchema,
5
- EmptyResultSchema,
6
- ErrorCode,
7
- GetPromptResultSchema,
8
- InitializeResultSchema,
9
- LATEST_PROTOCOL_VERSION,
10
- ListPromptsResultSchema,
11
- ListResourceTemplatesResultSchema,
12
- ListResourcesResultSchema,
13
- ListToolsResultSchema,
14
- McpError,
15
- PingRequestSchema,
16
- ProgressNotificationSchema,
17
- PromptListChangedNotificationSchema,
18
- ReadResourceResultSchema,
19
- ResourceListChangedNotificationSchema,
20
- SSEEdgeClientTransport,
21
- SUPPORTED_PROTOCOL_VERSIONS,
22
- ToolListChangedNotificationSchema
23
- } from "../chunk-EZ76ZGDB.js";
1
+ import "../chunk-HMLY7DHA.js";
24
2
 
25
- // ../../node_modules/@modelcontextprotocol/sdk/dist/esm/shared/protocol.js
26
- var DEFAULT_REQUEST_TIMEOUT_MSEC = 6e4;
27
- var Protocol = class {
28
- constructor(_options) {
29
- this._options = _options;
30
- this._requestMessageId = 0;
31
- this._requestHandlers = /* @__PURE__ */ new Map();
32
- this._requestHandlerAbortControllers = /* @__PURE__ */ new Map();
33
- this._notificationHandlers = /* @__PURE__ */ new Map();
34
- this._responseHandlers = /* @__PURE__ */ new Map();
35
- this._progressHandlers = /* @__PURE__ */ new Map();
36
- this._timeoutInfo = /* @__PURE__ */ new Map();
37
- this.setNotificationHandler(CancelledNotificationSchema, (notification) => {
38
- const controller = this._requestHandlerAbortControllers.get(notification.params.requestId);
39
- controller === null || controller === void 0 ? void 0 : controller.abort(notification.params.reason);
40
- });
41
- this.setNotificationHandler(ProgressNotificationSchema, (notification) => {
42
- this._onprogress(notification);
43
- });
44
- this.setRequestHandler(
45
- PingRequestSchema,
46
- // Automatic pong by default.
47
- (_request) => ({})
48
- );
49
- }
50
- _setupTimeout(messageId, timeout, maxTotalTimeout, onTimeout) {
51
- this._timeoutInfo.set(messageId, {
52
- timeoutId: setTimeout(onTimeout, timeout),
53
- startTime: Date.now(),
54
- timeout,
55
- maxTotalTimeout,
56
- onTimeout
57
- });
58
- }
59
- _resetTimeout(messageId) {
60
- const info = this._timeoutInfo.get(messageId);
61
- if (!info)
62
- return false;
63
- const totalElapsed = Date.now() - info.startTime;
64
- if (info.maxTotalTimeout && totalElapsed >= info.maxTotalTimeout) {
65
- this._timeoutInfo.delete(messageId);
66
- throw new McpError(ErrorCode.RequestTimeout, "Maximum total timeout exceeded", { maxTotalTimeout: info.maxTotalTimeout, totalElapsed });
67
- }
68
- clearTimeout(info.timeoutId);
69
- info.timeoutId = setTimeout(info.onTimeout, info.timeout);
70
- return true;
71
- }
72
- _cleanupTimeout(messageId) {
73
- const info = this._timeoutInfo.get(messageId);
74
- if (info) {
75
- clearTimeout(info.timeoutId);
76
- this._timeoutInfo.delete(messageId);
77
- }
78
- }
3
+ // src/mcp/sse-edge.ts
4
+ import {
5
+ SSEClientTransport
6
+ } from "@modelcontextprotocol/sdk/client/sse.js";
7
+ var SSEEdgeClientTransport = class extends SSEClientTransport {
79
8
  /**
80
- * Attaches to the given transport, starts it, and starts listening for messages.
81
- *
82
- * The Protocol object assumes ownership of the Transport, replacing any callbacks that have already been set, and expects that it is the only user of the Transport instance going forward.
9
+ * Creates a new EdgeSSEClientTransport, which overrides fetch to be compatible with the CF workers environment
83
10
  */
84
- async connect(transport) {
85
- this._transport = transport;
86
- this._transport.onclose = () => {
87
- this._onclose();
88
- };
89
- this._transport.onerror = (error) => {
90
- this._onerror(error);
91
- };
92
- this._transport.onmessage = (message) => {
93
- if (!("method" in message)) {
94
- this._onresponse(message);
95
- } else if ("id" in message) {
96
- this._onrequest(message);
97
- } else {
98
- this._onnotification(message);
99
- }
100
- };
101
- await this._transport.start();
102
- }
103
- _onclose() {
104
- var _a;
105
- const responseHandlers = this._responseHandlers;
106
- this._responseHandlers = /* @__PURE__ */ new Map();
107
- this._progressHandlers.clear();
108
- this._transport = void 0;
109
- (_a = this.onclose) === null || _a === void 0 ? void 0 : _a.call(this);
110
- const error = new McpError(ErrorCode.ConnectionClosed, "Connection closed");
111
- for (const handler of responseHandlers.values()) {
112
- handler(error);
113
- }
114
- }
115
- _onerror(error) {
116
- var _a;
117
- (_a = this.onerror) === null || _a === void 0 ? void 0 : _a.call(this, error);
118
- }
119
- _onnotification(notification) {
120
- var _a;
121
- const handler = (_a = this._notificationHandlers.get(notification.method)) !== null && _a !== void 0 ? _a : this.fallbackNotificationHandler;
122
- if (handler === void 0) {
123
- return;
124
- }
125
- Promise.resolve().then(() => handler(notification)).catch((error) => this._onerror(new Error(`Uncaught error in notification handler: ${error}`)));
126
- }
127
- _onrequest(request) {
128
- var _a, _b, _c;
129
- const handler = (_a = this._requestHandlers.get(request.method)) !== null && _a !== void 0 ? _a : this.fallbackRequestHandler;
130
- if (handler === void 0) {
131
- (_b = this._transport) === null || _b === void 0 ? void 0 : _b.send({
132
- jsonrpc: "2.0",
133
- id: request.id,
134
- error: {
135
- code: ErrorCode.MethodNotFound,
136
- message: "Method not found"
11
+ constructor(url, options) {
12
+ const fetchOverride = async (fetchUrl, fetchInit = {}) => {
13
+ const headers = await this.authHeaders();
14
+ const workerOptions = {
15
+ ...fetchInit,
16
+ headers: {
17
+ ...fetchInit?.headers,
18
+ ...headers
137
19
  }
138
- }).catch((error) => this._onerror(new Error(`Failed to send an error response: ${error}`)));
139
- return;
140
- }
141
- const abortController = new AbortController();
142
- this._requestHandlerAbortControllers.set(request.id, abortController);
143
- const extra = {
144
- signal: abortController.signal,
145
- sessionId: (_c = this._transport) === null || _c === void 0 ? void 0 : _c.sessionId
20
+ };
21
+ delete workerOptions.mode;
22
+ return fetch(fetchUrl, workerOptions);
146
23
  };
147
- Promise.resolve().then(() => handler(request, extra)).then((result) => {
148
- var _a2;
149
- if (abortController.signal.aborted) {
150
- return;
24
+ super(url, {
25
+ ...options,
26
+ eventSourceInit: {
27
+ fetch: fetchOverride
151
28
  }
152
- return (_a2 = this._transport) === null || _a2 === void 0 ? void 0 : _a2.send({
153
- result,
154
- jsonrpc: "2.0",
155
- id: request.id
156
- });
157
- }, (error) => {
158
- var _a2, _b2;
159
- if (abortController.signal.aborted) {
160
- return;
161
- }
162
- return (_a2 = this._transport) === null || _a2 === void 0 ? void 0 : _a2.send({
163
- jsonrpc: "2.0",
164
- id: request.id,
165
- error: {
166
- code: Number.isSafeInteger(error["code"]) ? error["code"] : ErrorCode.InternalError,
167
- message: (_b2 = error.message) !== null && _b2 !== void 0 ? _b2 : "Internal error"
168
- }
169
- });
170
- }).catch((error) => this._onerror(new Error(`Failed to send response: ${error}`))).finally(() => {
171
- this._requestHandlerAbortControllers.delete(request.id);
172
29
  });
173
- }
174
- _onprogress(notification) {
175
- const { progressToken, ...params } = notification.params;
176
- const messageId = Number(progressToken);
177
- const handler = this._progressHandlers.get(messageId);
178
- if (!handler) {
179
- this._onerror(new Error(`Received a progress notification for an unknown token: ${JSON.stringify(notification)}`));
180
- return;
181
- }
182
- const responseHandler = this._responseHandlers.get(messageId);
183
- if (this._timeoutInfo.has(messageId) && responseHandler) {
184
- try {
185
- this._resetTimeout(messageId);
186
- } catch (error) {
187
- responseHandler(error);
188
- return;
189
- }
190
- }
191
- handler(params);
192
- }
193
- _onresponse(response) {
194
- const messageId = Number(response.id);
195
- const handler = this._responseHandlers.get(messageId);
196
- if (handler === void 0) {
197
- this._onerror(new Error(`Received a response for an unknown message ID: ${JSON.stringify(response)}`));
198
- return;
199
- }
200
- this._responseHandlers.delete(messageId);
201
- this._progressHandlers.delete(messageId);
202
- this._cleanupTimeout(messageId);
203
- if ("result" in response) {
204
- handler(response);
205
- } else {
206
- const error = new McpError(response.error.code, response.error.message, response.error.data);
207
- handler(error);
208
- }
209
- }
210
- get transport() {
211
- return this._transport;
212
- }
213
- /**
214
- * Closes the connection.
215
- */
216
- async close() {
217
- var _a;
218
- await ((_a = this._transport) === null || _a === void 0 ? void 0 : _a.close());
219
- }
220
- /**
221
- * Sends a request and wait for a response.
222
- *
223
- * Do not use this method to emit notifications! Use notification() instead.
224
- */
225
- request(request, resultSchema, options) {
226
- return new Promise((resolve, reject) => {
227
- var _a, _b, _c, _d;
228
- if (!this._transport) {
229
- reject(new Error("Not connected"));
230
- return;
231
- }
232
- if (((_a = this._options) === null || _a === void 0 ? void 0 : _a.enforceStrictCapabilities) === true) {
233
- this.assertCapabilityForMethod(request.method);
234
- }
235
- (_b = options === null || options === void 0 ? void 0 : options.signal) === null || _b === void 0 ? void 0 : _b.throwIfAborted();
236
- const messageId = this._requestMessageId++;
237
- const jsonrpcRequest = {
238
- ...request,
239
- jsonrpc: "2.0",
240
- id: messageId
241
- };
242
- if (options === null || options === void 0 ? void 0 : options.onprogress) {
243
- this._progressHandlers.set(messageId, options.onprogress);
244
- jsonrpcRequest.params = {
245
- ...request.params,
246
- _meta: { progressToken: messageId }
30
+ this.authProvider = options.authProvider;
31
+ }
32
+ async authHeaders() {
33
+ if (this.authProvider) {
34
+ const tokens = await this.authProvider.tokens();
35
+ if (tokens) {
36
+ return {
37
+ Authorization: `Bearer ${tokens.access_token}`
247
38
  };
248
39
  }
249
- const cancel = (reason) => {
250
- var _a2;
251
- this._responseHandlers.delete(messageId);
252
- this._progressHandlers.delete(messageId);
253
- this._cleanupTimeout(messageId);
254
- (_a2 = this._transport) === null || _a2 === void 0 ? void 0 : _a2.send({
255
- jsonrpc: "2.0",
256
- method: "notifications/cancelled",
257
- params: {
258
- requestId: messageId,
259
- reason: String(reason)
260
- }
261
- }).catch((error) => this._onerror(new Error(`Failed to send cancellation: ${error}`)));
262
- reject(reason);
263
- };
264
- this._responseHandlers.set(messageId, (response) => {
265
- var _a2;
266
- if ((_a2 = options === null || options === void 0 ? void 0 : options.signal) === null || _a2 === void 0 ? void 0 : _a2.aborted) {
267
- return;
268
- }
269
- if (response instanceof Error) {
270
- return reject(response);
271
- }
272
- try {
273
- const result = resultSchema.parse(response.result);
274
- resolve(result);
275
- } catch (error) {
276
- reject(error);
277
- }
278
- });
279
- (_c = options === null || options === void 0 ? void 0 : options.signal) === null || _c === void 0 ? void 0 : _c.addEventListener("abort", () => {
280
- var _a2;
281
- cancel((_a2 = options === null || options === void 0 ? void 0 : options.signal) === null || _a2 === void 0 ? void 0 : _a2.reason);
282
- });
283
- const timeout = (_d = options === null || options === void 0 ? void 0 : options.timeout) !== null && _d !== void 0 ? _d : DEFAULT_REQUEST_TIMEOUT_MSEC;
284
- const timeoutHandler = () => cancel(new McpError(ErrorCode.RequestTimeout, "Request timed out", { timeout }));
285
- this._setupTimeout(messageId, timeout, options === null || options === void 0 ? void 0 : options.maxTotalTimeout, timeoutHandler);
286
- this._transport.send(jsonrpcRequest).catch((error) => {
287
- this._cleanupTimeout(messageId);
288
- reject(error);
289
- });
290
- });
291
- }
292
- /**
293
- * Emits a notification, which is a one-way message that does not expect a response.
294
- */
295
- async notification(notification) {
296
- if (!this._transport) {
297
- throw new Error("Not connected");
298
- }
299
- this.assertNotificationCapability(notification.method);
300
- const jsonrpcNotification = {
301
- ...notification,
302
- jsonrpc: "2.0"
303
- };
304
- await this._transport.send(jsonrpcNotification);
305
- }
306
- /**
307
- * Registers a handler to invoke when this protocol object receives a request with the given method.
308
- *
309
- * Note that this will replace any previous request handler for the same method.
310
- */
311
- setRequestHandler(requestSchema, handler) {
312
- const method = requestSchema.shape.method.value;
313
- this.assertRequestHandlerCapability(method);
314
- this._requestHandlers.set(method, (request, extra) => Promise.resolve(handler(requestSchema.parse(request), extra)));
315
- }
316
- /**
317
- * Removes the request handler for the given method.
318
- */
319
- removeRequestHandler(method) {
320
- this._requestHandlers.delete(method);
321
- }
322
- /**
323
- * Asserts that a request handler has not already been set for the given method, in preparation for a new one being automatically installed.
324
- */
325
- assertCanSetRequestHandler(method) {
326
- if (this._requestHandlers.has(method)) {
327
- throw new Error(`A request handler for ${method} already exists, which would be overridden`);
328
- }
329
- }
330
- /**
331
- * Registers a handler to invoke when this protocol object receives a notification with the given method.
332
- *
333
- * Note that this will replace any previous notification handler for the same method.
334
- */
335
- setNotificationHandler(notificationSchema, handler) {
336
- this._notificationHandlers.set(notificationSchema.shape.method.value, (notification) => Promise.resolve(handler(notificationSchema.parse(notification))));
337
- }
338
- /**
339
- * Removes the notification handler for the given method.
340
- */
341
- removeNotificationHandler(method) {
342
- this._notificationHandlers.delete(method);
343
- }
344
- };
345
- function mergeCapabilities(base, additional) {
346
- return Object.entries(additional).reduce((acc, [key, value]) => {
347
- if (value && typeof value === "object") {
348
- acc[key] = acc[key] ? { ...acc[key], ...value } : value;
349
- } else {
350
- acc[key] = value;
351
- }
352
- return acc;
353
- }, { ...base });
354
- }
355
-
356
- // ../../node_modules/@modelcontextprotocol/sdk/dist/esm/client/index.js
357
- var Client = class extends Protocol {
358
- /**
359
- * Initializes this client with the given name and version information.
360
- */
361
- constructor(_clientInfo, options) {
362
- var _a;
363
- super(options);
364
- this._clientInfo = _clientInfo;
365
- this._capabilities = (_a = options === null || options === void 0 ? void 0 : options.capabilities) !== null && _a !== void 0 ? _a : {};
366
- }
367
- /**
368
- * Registers new capabilities. This can only be called before connecting to a transport.
369
- *
370
- * The new capabilities will be merged with any existing capabilities previously given (e.g., at initialization).
371
- */
372
- registerCapabilities(capabilities) {
373
- if (this.transport) {
374
- throw new Error("Cannot register capabilities after connecting to transport");
375
- }
376
- this._capabilities = mergeCapabilities(this._capabilities, capabilities);
377
- }
378
- assertCapability(capability, method) {
379
- var _a;
380
- if (!((_a = this._serverCapabilities) === null || _a === void 0 ? void 0 : _a[capability])) {
381
- throw new Error(`Server does not support ${capability} (required for ${method})`);
382
- }
383
- }
384
- async connect(transport) {
385
- await super.connect(transport);
386
- try {
387
- const result = await this.request({
388
- method: "initialize",
389
- params: {
390
- protocolVersion: LATEST_PROTOCOL_VERSION,
391
- capabilities: this._capabilities,
392
- clientInfo: this._clientInfo
393
- }
394
- }, InitializeResultSchema);
395
- if (result === void 0) {
396
- throw new Error(`Server sent invalid initialize result: ${result}`);
397
- }
398
- if (!SUPPORTED_PROTOCOL_VERSIONS.includes(result.protocolVersion)) {
399
- throw new Error(`Server's protocol version is not supported: ${result.protocolVersion}`);
400
- }
401
- this._serverCapabilities = result.capabilities;
402
- this._serverVersion = result.serverInfo;
403
- this._instructions = result.instructions;
404
- await this.notification({
405
- method: "notifications/initialized"
406
- });
407
- } catch (error) {
408
- void this.close();
409
- throw error;
410
- }
411
- }
412
- /**
413
- * After initialization has completed, this will be populated with the server's reported capabilities.
414
- */
415
- getServerCapabilities() {
416
- return this._serverCapabilities;
417
- }
418
- /**
419
- * After initialization has completed, this will be populated with information about the server's name and version.
420
- */
421
- getServerVersion() {
422
- return this._serverVersion;
423
- }
424
- /**
425
- * After initialization has completed, this may be populated with information about the server's instructions.
426
- */
427
- getInstructions() {
428
- return this._instructions;
429
- }
430
- assertCapabilityForMethod(method) {
431
- var _a, _b, _c, _d, _e;
432
- switch (method) {
433
- case "logging/setLevel":
434
- if (!((_a = this._serverCapabilities) === null || _a === void 0 ? void 0 : _a.logging)) {
435
- throw new Error(`Server does not support logging (required for ${method})`);
436
- }
437
- break;
438
- case "prompts/get":
439
- case "prompts/list":
440
- if (!((_b = this._serverCapabilities) === null || _b === void 0 ? void 0 : _b.prompts)) {
441
- throw new Error(`Server does not support prompts (required for ${method})`);
442
- }
443
- break;
444
- case "resources/list":
445
- case "resources/templates/list":
446
- case "resources/read":
447
- case "resources/subscribe":
448
- case "resources/unsubscribe":
449
- if (!((_c = this._serverCapabilities) === null || _c === void 0 ? void 0 : _c.resources)) {
450
- throw new Error(`Server does not support resources (required for ${method})`);
451
- }
452
- if (method === "resources/subscribe" && !this._serverCapabilities.resources.subscribe) {
453
- throw new Error(`Server does not support resource subscriptions (required for ${method})`);
454
- }
455
- break;
456
- case "tools/call":
457
- case "tools/list":
458
- if (!((_d = this._serverCapabilities) === null || _d === void 0 ? void 0 : _d.tools)) {
459
- throw new Error(`Server does not support tools (required for ${method})`);
460
- }
461
- break;
462
- case "completion/complete":
463
- if (!((_e = this._serverCapabilities) === null || _e === void 0 ? void 0 : _e.prompts)) {
464
- throw new Error(`Server does not support prompts (required for ${method})`);
465
- }
466
- break;
467
- case "initialize":
468
- break;
469
- case "ping":
470
- break;
471
- }
472
- }
473
- assertNotificationCapability(method) {
474
- var _a;
475
- switch (method) {
476
- case "notifications/roots/list_changed":
477
- if (!((_a = this._capabilities.roots) === null || _a === void 0 ? void 0 : _a.listChanged)) {
478
- throw new Error(`Client does not support roots list changed notifications (required for ${method})`);
479
- }
480
- break;
481
- case "notifications/initialized":
482
- break;
483
- case "notifications/cancelled":
484
- break;
485
- case "notifications/progress":
486
- break;
487
- }
488
- }
489
- assertRequestHandlerCapability(method) {
490
- switch (method) {
491
- case "sampling/createMessage":
492
- if (!this._capabilities.sampling) {
493
- throw new Error(`Client does not support sampling capability (required for ${method})`);
494
- }
495
- break;
496
- case "roots/list":
497
- if (!this._capabilities.roots) {
498
- throw new Error(`Client does not support roots capability (required for ${method})`);
499
- }
500
- break;
501
- case "ping":
502
- break;
503
40
  }
504
41
  }
505
- async ping(options) {
506
- return this.request({ method: "ping" }, EmptyResultSchema, options);
507
- }
508
- async complete(params, options) {
509
- return this.request({ method: "completion/complete", params }, CompleteResultSchema, options);
510
- }
511
- async setLoggingLevel(level, options) {
512
- return this.request({ method: "logging/setLevel", params: { level } }, EmptyResultSchema, options);
513
- }
514
- async getPrompt(params, options) {
515
- return this.request({ method: "prompts/get", params }, GetPromptResultSchema, options);
516
- }
517
- async listPrompts(params, options) {
518
- return this.request({ method: "prompts/list", params }, ListPromptsResultSchema, options);
519
- }
520
- async listResources(params, options) {
521
- return this.request({ method: "resources/list", params }, ListResourcesResultSchema, options);
522
- }
523
- async listResourceTemplates(params, options) {
524
- return this.request({ method: "resources/templates/list", params }, ListResourceTemplatesResultSchema, options);
525
- }
526
- async readResource(params, options) {
527
- return this.request({ method: "resources/read", params }, ReadResourceResultSchema, options);
528
- }
529
- async subscribeResource(params, options) {
530
- return this.request({ method: "resources/subscribe", params }, EmptyResultSchema, options);
531
- }
532
- async unsubscribeResource(params, options) {
533
- return this.request({ method: "resources/unsubscribe", params }, EmptyResultSchema, options);
534
- }
535
- async callTool(params, resultSchema = CallToolResultSchema, options) {
536
- return this.request({ method: "tools/call", params }, resultSchema, options);
537
- }
538
- async listTools(params, options) {
539
- return this.request({ method: "tools/list", params }, ListToolsResultSchema, options);
540
- }
541
- async sendRootsListChanged() {
542
- return this.notification({ method: "notifications/roots/list_changed" });
543
- }
544
42
  };
545
43
 
546
44
  // src/mcp/client-connection.ts
45
+ import {
46
+ ToolListChangedNotificationSchema,
47
+ ResourceListChangedNotificationSchema,
48
+ PromptListChangedNotificationSchema
49
+ } from "@modelcontextprotocol/sdk/types.js";
50
+ import { Client } from "@modelcontextprotocol/sdk/client/index.js";
547
51
  var MCPClientConnection = class {
548
- constructor(url, info, opts = { transport: {}, client: {}, capabilities: {} }) {
52
+ constructor(url, info, options = { transport: {}, client: {}, capabilities: {} }) {
53
+ this.url = url;
549
54
  this.info = info;
550
- this.transport = new SSEEdgeClientTransport(url, opts.transport);
551
- this.client = new Client(info, opts.client);
552
- this.client.registerCapabilities(opts.capabilities);
553
- this.connected = false;
55
+ this.options = options;
56
+ this.connectionState = "connecting";
554
57
  this.tools = [];
555
58
  this.prompts = [];
556
59
  this.resources = [];
557
60
  this.resourceTemplates = [];
61
+ this.client = new Client(info, options.client);
62
+ this.client.registerCapabilities(options.capabilities);
558
63
  }
559
- client;
560
- transport;
561
- connected;
562
- instructions;
563
- tools;
564
- prompts;
565
- resources;
566
- resourceTemplates;
567
- serverCapabilities;
568
- async init() {
569
- await this.client.connect(this.transport);
64
+ /**
65
+ * Initialize a client connection
66
+ *
67
+ * @param code Optional OAuth code to initialize the connection with if auth hasn't been initialized
68
+ * @returns
69
+ */
70
+ async init(code, clientId) {
71
+ try {
72
+ const transport = new SSEEdgeClientTransport(
73
+ this.url,
74
+ this.options.transport
75
+ );
76
+ if (code) {
77
+ await transport.finishAuth(code);
78
+ }
79
+ await this.client.connect(transport);
80
+ } catch (e) {
81
+ if (e.toString().includes("Unauthorized")) {
82
+ this.connectionState = "authenticating";
83
+ return;
84
+ }
85
+ this.connectionState = "failed";
86
+ throw e;
87
+ }
88
+ this.connectionState = "discovering";
570
89
  this.serverCapabilities = await this.client.getServerCapabilities();
571
90
  if (!this.serverCapabilities) {
572
- throw new Error(
573
- `The MCP Server ${this.info.name} failed to return server capabilities`
574
- );
91
+ throw new Error("The MCP Server failed to return server capabilities");
575
92
  }
576
93
  const [instructions, tools, resources, prompts, resourceTemplates] = await Promise.all([
577
94
  this.client.getInstructions(),
@@ -585,6 +102,7 @@ var MCPClientConnection = class {
585
102
  this.resources = resources;
586
103
  this.prompts = prompts;
587
104
  this.resourceTemplates = resourceTemplates;
105
+ this.connectionState = "ready";
588
106
  }
589
107
  /**
590
108
  * Notification handler registration
@@ -685,9 +203,111 @@ var MCPClientConnection = class {
685
203
  }
686
204
  };
687
205
 
206
+ // src/mcp/do-oauth-client-provider.ts
207
+ var DurableObjectOAuthClientProvider = class {
208
+ constructor(storage, clientName, sessionId, redirectUrl, clientId_) {
209
+ this.storage = storage;
210
+ this.clientName = clientName;
211
+ this.sessionId = sessionId;
212
+ this.redirectUrl = redirectUrl;
213
+ this.clientId_ = clientId_;
214
+ }
215
+ get clientMetadata() {
216
+ return {
217
+ redirect_uris: [this.redirectUrl],
218
+ token_endpoint_auth_method: "none",
219
+ grant_types: ["authorization_code", "refresh_token"],
220
+ response_types: ["code"],
221
+ client_name: this.clientName,
222
+ client_uri: "example.com"
223
+ };
224
+ }
225
+ get clientId() {
226
+ if (!this.clientId_) {
227
+ throw new Error("no clientId");
228
+ }
229
+ return this.clientId_;
230
+ }
231
+ set clientId(clientId_) {
232
+ this.clientId_ = clientId_;
233
+ }
234
+ keyPrefix(clientId) {
235
+ return `/${this.clientName}/${this.sessionId}/${clientId}`;
236
+ }
237
+ clientInfoKey(clientId) {
238
+ return `${this.keyPrefix(clientId)}/client_info/`;
239
+ }
240
+ async clientInformation() {
241
+ if (!this.clientId_) {
242
+ return void 0;
243
+ }
244
+ return await this.storage.get(
245
+ this.clientInfoKey(this.clientId)
246
+ ) ?? void 0;
247
+ }
248
+ async saveClientInformation(clientInformation) {
249
+ await this.storage.put(
250
+ this.clientInfoKey(clientInformation.client_id),
251
+ clientInformation
252
+ );
253
+ this.clientId = clientInformation.client_id;
254
+ }
255
+ tokenKey(clientId) {
256
+ return `${this.keyPrefix(clientId)}/token`;
257
+ }
258
+ async tokens() {
259
+ if (!this.clientId_) {
260
+ return void 0;
261
+ }
262
+ return await this.storage.get(this.tokenKey(this.clientId)) ?? void 0;
263
+ }
264
+ async saveTokens(tokens) {
265
+ await this.storage.put(this.tokenKey(this.clientId), tokens);
266
+ }
267
+ get authUrl() {
268
+ return this.authUrl_;
269
+ }
270
+ /**
271
+ * Because this operates on the server side (but we need browser auth), we send this url back to the user
272
+ * and require user interact to initiate the redirect flow
273
+ */
274
+ async redirectToAuthorization(authUrl) {
275
+ const client_id = authUrl.searchParams.get("client_id");
276
+ if (client_id) {
277
+ authUrl.searchParams.append("state", client_id);
278
+ }
279
+ this.authUrl_ = authUrl.toString();
280
+ }
281
+ codeVerifierKey(clientId) {
282
+ return `${this.keyPrefix(clientId)}/code_verifier`;
283
+ }
284
+ async saveCodeVerifier(verifier) {
285
+ await this.storage.put(this.codeVerifierKey(this.clientId), verifier);
286
+ }
287
+ async codeVerifier() {
288
+ const codeVerifier = await this.storage.get(
289
+ this.codeVerifierKey(this.clientId)
290
+ );
291
+ if (!codeVerifier) {
292
+ throw new Error("No code verifier found");
293
+ }
294
+ return codeVerifier;
295
+ }
296
+ };
297
+
688
298
  // src/mcp/client.ts
689
299
  var MCPClientManager = class {
690
- mcpConnections = {};
300
+ /**
301
+ * @param name Name of the MCP client
302
+ * @param version Version of the MCP Client
303
+ * @param auth Auth paramters if being used to create a DurableObjectOAuthClientProvider
304
+ */
305
+ constructor(name, version, auth) {
306
+ this.name = name;
307
+ this.version = version;
308
+ this.auth = auth;
309
+ this.mcpConnections = {};
310
+ }
691
311
  /**
692
312
  * Connect to and register an MCP server
693
313
  *
@@ -695,14 +315,82 @@ var MCPClientManager = class {
695
315
  * @param clientConfig Client config
696
316
  * @param capabilities Client capabilities (i.e. if the client supports roots/sampling)
697
317
  */
698
- async connectToServer(url, info, opts = { transport: {}, client: {}, capabilities: {} }) {
699
- if (info.name in this.mcpConnections) {
318
+ async connect(url, opts = {}) {
319
+ const id = opts.reconnect?.id ?? crypto.randomUUID();
320
+ if (this.auth) {
321
+ console.warn(
322
+ "Using .auth configuration to generate an oauth provider, this is temporary and will be removed in the next version. Instead use transport.authProvider to provide an auth provider"
323
+ );
324
+ }
325
+ const authProvider = this.auth ? new DurableObjectOAuthClientProvider(
326
+ this.auth.storage,
327
+ this.name,
328
+ id,
329
+ `${this.auth.baseCallbackUri}/${id}`,
330
+ opts.reconnect?.oauthClientId
331
+ ) : opts.transport?.authProvider;
332
+ this.mcpConnections[id] = new MCPClientConnection(
333
+ new URL(url),
334
+ {
335
+ name: this.name,
336
+ version: this.version
337
+ },
338
+ {
339
+ transport: {
340
+ ...opts.transport,
341
+ authProvider
342
+ },
343
+ client: opts.client ?? {},
344
+ capabilities: opts.client ?? {}
345
+ }
346
+ );
347
+ await this.mcpConnections[id].init(
348
+ opts.reconnect?.oauthCode,
349
+ opts.reconnect?.oauthClientId
350
+ );
351
+ return {
352
+ id,
353
+ authUrl: authProvider?.authUrl
354
+ };
355
+ }
356
+ isCallbackRequest(req) {
357
+ if (this.auth?.baseCallbackUri) {
358
+ return req.url.startsWith(this.auth.baseCallbackUri) && req.method === "GET";
359
+ }
360
+ return false;
361
+ }
362
+ async handleCallbackRequest(req) {
363
+ const url = new URL(req.url);
364
+ const code = url.searchParams.get("code");
365
+ const clientId = url.searchParams.get("state");
366
+ let serverId = req.url.replace(this.auth.baseCallbackUri, "").split("?")[0];
367
+ serverId = serverId.replaceAll("/", "");
368
+ if (!code) {
369
+ throw new Error("Unauthorized: no code provided");
370
+ }
371
+ if (!clientId) {
372
+ throw new Error("Unauthorized: no state provided");
373
+ }
374
+ if (this.mcpConnections[serverId] === void 0) {
375
+ throw new Error(`Could not find serverId: ${serverId}`);
376
+ }
377
+ if (this.mcpConnections[serverId].connectionState !== "authenticating") {
700
378
  throw new Error(
701
- `An existing MCP client has already been registered under the name "${info.name}". The MCP client name must be unique.`
379
+ "Failed to authenticate: the client isn't in the `authenticating` state"
702
380
  );
703
381
  }
704
- this.mcpConnections[info.name] = new MCPClientConnection(url, info, opts);
705
- await this.mcpConnections[info.name].init();
382
+ const serverUrl = this.mcpConnections[serverId].url.toString();
383
+ await this.connect(serverUrl, {
384
+ reconnect: {
385
+ id: serverId,
386
+ oauthClientId: clientId,
387
+ oauthCode: code
388
+ }
389
+ });
390
+ if (this.mcpConnections[serverId].connectionState === "authenticating") {
391
+ throw new Error("Failed to authenticate: client failed to initialize");
392
+ }
393
+ return { serverId };
706
394
  }
707
395
  /**
708
396
  * @returns namespaced list of tools
@@ -732,8 +420,8 @@ var MCPClientManager = class {
732
420
  * Namespaced version of callTool
733
421
  */
734
422
  callTool(params, resultSchema, options) {
735
- const unqualifiedName = params.name.replace(`${params.serverName}.`, "");
736
- return this.mcpConnections[params.serverName].client.callTool(
423
+ const unqualifiedName = params.name.replace(`${params.serverId}.`, "");
424
+ return this.mcpConnections[params.serverId].client.callTool(
737
425
  {
738
426
  ...params,
739
427
  name: unqualifiedName
@@ -746,7 +434,7 @@ var MCPClientManager = class {
746
434
  * Namespaced version of readResource
747
435
  */
748
436
  readResource(params, options) {
749
- return this.mcpConnections[params.serverName].client.readResource(
437
+ return this.mcpConnections[params.serverId].client.readResource(
750
438
  params,
751
439
  options
752
440
  );
@@ -755,7 +443,7 @@ var MCPClientManager = class {
755
443
  * Namespaced version of getPrompt
756
444
  */
757
445
  getPrompt(params, options) {
758
- return this.mcpConnections[params.serverName].client.getPrompt(
446
+ return this.mcpConnections[params.serverId].client.getPrompt(
759
447
  params,
760
448
  options
761
449
  );
@@ -765,15 +453,12 @@ function getNamespacedData(mcpClients, type) {
765
453
  const sets = Object.entries(mcpClients).map(([name, conn]) => {
766
454
  return { name, data: conn[type] };
767
455
  });
768
- const namespacedData = sets.flatMap(({ name: serverName, data }) => {
456
+ const namespacedData = sets.flatMap(({ name: serverId, data }) => {
769
457
  return data.map((item) => {
770
458
  return {
771
459
  ...item,
772
- // we add a servername so we can easily pull it out and convert between qualified<->unqualified name
773
- // just in case the server name or item name includes a "."
774
- serverName: `${serverName}`,
775
- // qualified name
776
- name: `${serverName}.${item.name}`
460
+ // we add a serverId so we can easily pull it out and send the tool call to the right server
461
+ serverId
777
462
  };
778
463
  });
779
464
  });