agents 0.0.0-ced3b22 → 0.0.0-cf3b3d7

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.
Files changed (85) hide show
  1. package/README.md +103 -5
  2. package/dist/ai-chat-agent.d.ts +16 -17
  3. package/dist/ai-chat-agent.js +532 -343
  4. package/dist/ai-chat-agent.js.map +1 -1
  5. package/dist/ai-chat-v5-migration-DBHGW4Hv.js +155 -0
  6. package/dist/ai-chat-v5-migration-DBHGW4Hv.js.map +1 -0
  7. package/dist/ai-chat-v5-migration.d.ts +7 -4
  8. package/dist/ai-chat-v5-migration.js +3 -19
  9. package/dist/ai-react.d.ts +20 -23
  10. package/dist/ai-react.js +264 -304
  11. package/dist/ai-react.js.map +1 -1
  12. package/dist/ai-types-B3aQaFv3.js +20 -0
  13. package/dist/ai-types-B3aQaFv3.js.map +1 -0
  14. package/dist/ai-types-D5YoPrBZ.d.ts +95 -0
  15. package/dist/ai-types.d.ts +6 -91
  16. package/dist/ai-types.js +3 -7
  17. package/dist/cli.d.ts +8 -0
  18. package/dist/cli.js +27 -0
  19. package/dist/cli.js.map +1 -0
  20. package/dist/client-BaCHMay9.d.ts +5427 -0
  21. package/dist/client-BfiZ3HQd.js +117 -0
  22. package/dist/client-BfiZ3HQd.js.map +1 -0
  23. package/dist/client-CbWe9FBd.d.ts +104 -0
  24. package/dist/client-DpkZyXgJ.js +901 -0
  25. package/dist/client-DpkZyXgJ.js.map +1 -0
  26. package/dist/client.d.ts +11 -92
  27. package/dist/client.js +4 -12
  28. package/dist/codemode/ai.d.ts +27 -0
  29. package/dist/codemode/ai.js +151 -0
  30. package/dist/codemode/ai.js.map +1 -0
  31. package/dist/do-oauth-client-provider-CnbnngL2.d.ts +134 -0
  32. package/dist/do-oauth-client-provider-D2P1lSft.js +93 -0
  33. package/dist/do-oauth-client-provider-D2P1lSft.js.map +1 -0
  34. package/dist/index-DCRAdW9R.d.ts +572 -0
  35. package/dist/index-DhJCaDWd.d.ts +58 -0
  36. package/dist/index.d.ts +56 -550
  37. package/dist/index.js +7 -31
  38. package/dist/mcp/client.d.ts +4 -11
  39. package/dist/mcp/client.js +4 -9
  40. package/dist/mcp/do-oauth-client-provider.d.ts +2 -42
  41. package/dist/mcp/do-oauth-client-provider.js +3 -7
  42. package/dist/mcp/index.d.ts +188 -92
  43. package/dist/mcp/index.js +1423 -1012
  44. package/dist/mcp/index.js.map +1 -1
  45. package/dist/mcp/x402.d.ts +34 -0
  46. package/dist/mcp/x402.js +194 -0
  47. package/dist/mcp/x402.js.map +1 -0
  48. package/dist/mcp-Dw5vDrY8.d.ts +61 -0
  49. package/dist/observability/index.d.ts +3 -46
  50. package/dist/observability/index.js +7 -11
  51. package/dist/react-DM_FD53F.d.ts +113 -0
  52. package/dist/react.d.ts +10 -123
  53. package/dist/react.js +183 -112
  54. package/dist/react.js.map +1 -1
  55. package/dist/schedule.d.ts +13 -10
  56. package/dist/schedule.js +43 -31
  57. package/dist/schedule.js.map +1 -1
  58. package/dist/serializable-CymX8ovI.d.ts +39 -0
  59. package/dist/serializable.d.ts +7 -32
  60. package/dist/serializable.js +1 -1
  61. package/dist/src-Dk8lwxHf.js +1243 -0
  62. package/dist/src-Dk8lwxHf.js.map +1 -0
  63. package/package.json +70 -32
  64. package/dist/ai-chat-v5-migration.js.map +0 -1
  65. package/dist/ai-types.js.map +0 -1
  66. package/dist/chunk-AVYJQSLW.js +0 -17
  67. package/dist/chunk-AVYJQSLW.js.map +0 -1
  68. package/dist/chunk-LL2AFX7V.js +0 -109
  69. package/dist/chunk-LL2AFX7V.js.map +0 -1
  70. package/dist/chunk-MH46VMM4.js +0 -612
  71. package/dist/chunk-MH46VMM4.js.map +0 -1
  72. package/dist/chunk-QEVM4BVL.js +0 -116
  73. package/dist/chunk-QEVM4BVL.js.map +0 -1
  74. package/dist/chunk-UJVEAURM.js +0 -150
  75. package/dist/chunk-UJVEAURM.js.map +0 -1
  76. package/dist/chunk-YDUDMOL6.js +0 -1296
  77. package/dist/chunk-YDUDMOL6.js.map +0 -1
  78. package/dist/client-CvaJdLQA.d.ts +0 -5015
  79. package/dist/client.js.map +0 -1
  80. package/dist/index.js.map +0 -1
  81. package/dist/mcp/client.js.map +0 -1
  82. package/dist/mcp/do-oauth-client-provider.js.map +0 -1
  83. package/dist/observability/index.js.map +0 -1
  84. package/dist/serializable.js.map +0 -1
  85. package/src/index.ts +0 -1947
@@ -0,0 +1,901 @@
1
+ import { t as DurableObjectOAuthClientProvider } from "./do-oauth-client-provider-D2P1lSft.js";
2
+ import { nanoid } from "nanoid";
3
+ import { CfWorkerJsonSchemaValidator } from "@modelcontextprotocol/sdk/validation/cfworker-provider.js";
4
+ import { Client } from "@modelcontextprotocol/sdk/client/index.js";
5
+ import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
6
+ import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
7
+ import { ElicitRequestSchema, PromptListChangedNotificationSchema, ResourceListChangedNotificationSchema, ToolListChangedNotificationSchema } from "@modelcontextprotocol/sdk/types.js";
8
+
9
+ //#region src/core/events.ts
10
+ function toDisposable(fn) {
11
+ return { dispose: fn };
12
+ }
13
+ var DisposableStore = class {
14
+ constructor() {
15
+ this._items = [];
16
+ }
17
+ add(d) {
18
+ this._items.push(d);
19
+ return d;
20
+ }
21
+ dispose() {
22
+ while (this._items.length) try {
23
+ this._items.pop().dispose();
24
+ } catch {}
25
+ }
26
+ };
27
+ var Emitter = class {
28
+ constructor() {
29
+ this._listeners = /* @__PURE__ */ new Set();
30
+ this.event = (listener) => {
31
+ this._listeners.add(listener);
32
+ return toDisposable(() => this._listeners.delete(listener));
33
+ };
34
+ }
35
+ fire(data) {
36
+ for (const listener of [...this._listeners]) try {
37
+ listener(data);
38
+ } catch (err) {
39
+ console.error("Emitter listener error:", err);
40
+ }
41
+ }
42
+ dispose() {
43
+ this._listeners.clear();
44
+ }
45
+ };
46
+
47
+ //#endregion
48
+ //#region src/mcp/errors.ts
49
+ function toErrorMessage(error) {
50
+ return error instanceof Error ? error.message : String(error);
51
+ }
52
+ function isUnauthorized(error) {
53
+ const msg = toErrorMessage(error);
54
+ return msg.includes("Unauthorized") || msg.includes("401");
55
+ }
56
+ function isTransportNotImplemented(error) {
57
+ const msg = toErrorMessage(error);
58
+ return msg.includes("404") || msg.includes("405") || msg.includes("Not Implemented") || msg.includes("not implemented");
59
+ }
60
+
61
+ //#endregion
62
+ //#region src/mcp/client-connection.ts
63
+ var MCPClientConnection = class {
64
+ constructor(url, info, options = {
65
+ client: {},
66
+ transport: {}
67
+ }) {
68
+ this.url = url;
69
+ this.options = options;
70
+ this.connectionState = "connecting";
71
+ this.tools = [];
72
+ this.prompts = [];
73
+ this.resources = [];
74
+ this.resourceTemplates = [];
75
+ this._onObservabilityEvent = new Emitter();
76
+ this.onObservabilityEvent = this._onObservabilityEvent.event;
77
+ this.client = new Client(info, {
78
+ ...options.client,
79
+ capabilities: {
80
+ ...options.client?.capabilities,
81
+ elicitation: {}
82
+ }
83
+ });
84
+ }
85
+ /**
86
+ * Initialize a client connection
87
+ *
88
+ * @returns
89
+ */
90
+ async init() {
91
+ const transportType = this.options.transport.type;
92
+ if (!transportType) throw new Error("Transport type must be specified");
93
+ try {
94
+ await this.tryConnect(transportType);
95
+ } catch (e) {
96
+ if (isUnauthorized(e)) {
97
+ this.connectionState = "authenticating";
98
+ return;
99
+ }
100
+ this._onObservabilityEvent.fire({
101
+ type: "mcp:client:connect",
102
+ displayMessage: `Connection initialization failed for ${this.url.toString()}`,
103
+ payload: {
104
+ url: this.url.toString(),
105
+ transport: transportType,
106
+ state: this.connectionState,
107
+ error: toErrorMessage(e)
108
+ },
109
+ timestamp: Date.now(),
110
+ id: nanoid()
111
+ });
112
+ this.connectionState = "failed";
113
+ return;
114
+ }
115
+ await this.discoverAndRegister();
116
+ }
117
+ /**
118
+ * Finish OAuth by probing transports based on configured type.
119
+ * - Explicit: finish on that transport
120
+ * - Auto: try streamable-http, then sse on 404/405/Not Implemented
121
+ */
122
+ async finishAuthProbe(code) {
123
+ if (!this.options.transport.authProvider) throw new Error("No auth provider configured");
124
+ const configuredType = this.options.transport.type;
125
+ if (!configuredType) throw new Error("Transport type must be specified");
126
+ const finishAuth = async (base) => {
127
+ await this.getTransport(base).finishAuth(code);
128
+ };
129
+ if (configuredType === "sse" || configuredType === "streamable-http") {
130
+ await finishAuth(configuredType);
131
+ return;
132
+ }
133
+ try {
134
+ await finishAuth("streamable-http");
135
+ } catch (e) {
136
+ if (isTransportNotImplemented(e)) {
137
+ await finishAuth("sse");
138
+ return;
139
+ }
140
+ throw e;
141
+ }
142
+ }
143
+ /**
144
+ * Complete OAuth authorization
145
+ */
146
+ async completeAuthorization(code) {
147
+ if (this.connectionState !== "authenticating") throw new Error("Connection must be in authenticating state to complete authorization");
148
+ try {
149
+ await this.finishAuthProbe(code);
150
+ this.connectionState = "connecting";
151
+ } catch (error) {
152
+ this.connectionState = "failed";
153
+ throw error;
154
+ }
155
+ }
156
+ /**
157
+ * Establish connection after successful authorization
158
+ */
159
+ async establishConnection() {
160
+ if (this.connectionState !== "connecting") throw new Error("Connection must be in connecting state to establish connection");
161
+ try {
162
+ const transportType = this.options.transport.type;
163
+ if (!transportType) throw new Error("Transport type must be specified");
164
+ await this.tryConnect(transportType);
165
+ await this.discoverAndRegister();
166
+ } catch (error) {
167
+ this.connectionState = "failed";
168
+ throw error;
169
+ }
170
+ }
171
+ /**
172
+ * Discover server capabilities and register tools, resources, prompts, and templates
173
+ */
174
+ async discoverAndRegister() {
175
+ this.connectionState = "discovering";
176
+ this.serverCapabilities = this.client.getServerCapabilities();
177
+ if (!this.serverCapabilities) throw new Error("The MCP Server failed to return server capabilities");
178
+ const [instructionsResult, toolsResult, resourcesResult, promptsResult, resourceTemplatesResult] = await Promise.allSettled([
179
+ this.client.getInstructions(),
180
+ this.registerTools(),
181
+ this.registerResources(),
182
+ this.registerPrompts(),
183
+ this.registerResourceTemplates()
184
+ ]);
185
+ const operations = [
186
+ {
187
+ name: "instructions",
188
+ result: instructionsResult
189
+ },
190
+ {
191
+ name: "tools",
192
+ result: toolsResult
193
+ },
194
+ {
195
+ name: "resources",
196
+ result: resourcesResult
197
+ },
198
+ {
199
+ name: "prompts",
200
+ result: promptsResult
201
+ },
202
+ {
203
+ name: "resource templates",
204
+ result: resourceTemplatesResult
205
+ }
206
+ ];
207
+ for (const { name, result } of operations) if (result.status === "rejected") {
208
+ const url = this.url.toString();
209
+ this._onObservabilityEvent.fire({
210
+ type: "mcp:client:discover",
211
+ displayMessage: `Failed to discover ${name} for ${url}`,
212
+ payload: {
213
+ url,
214
+ capability: name,
215
+ error: result.reason
216
+ },
217
+ timestamp: Date.now(),
218
+ id: nanoid()
219
+ });
220
+ }
221
+ this.instructions = instructionsResult.status === "fulfilled" ? instructionsResult.value : void 0;
222
+ this.tools = toolsResult.status === "fulfilled" ? toolsResult.value : [];
223
+ this.resources = resourcesResult.status === "fulfilled" ? resourcesResult.value : [];
224
+ this.prompts = promptsResult.status === "fulfilled" ? promptsResult.value : [];
225
+ this.resourceTemplates = resourceTemplatesResult.status === "fulfilled" ? resourceTemplatesResult.value : [];
226
+ this.connectionState = "ready";
227
+ }
228
+ /**
229
+ * Notification handler registration
230
+ */
231
+ async registerTools() {
232
+ if (!this.serverCapabilities || !this.serverCapabilities.tools) return [];
233
+ if (this.serverCapabilities.tools.listChanged) this.client.setNotificationHandler(ToolListChangedNotificationSchema, async (_notification) => {
234
+ this.tools = await this.fetchTools();
235
+ });
236
+ return this.fetchTools();
237
+ }
238
+ async registerResources() {
239
+ if (!this.serverCapabilities || !this.serverCapabilities.resources) return [];
240
+ if (this.serverCapabilities.resources.listChanged) this.client.setNotificationHandler(ResourceListChangedNotificationSchema, async (_notification) => {
241
+ this.resources = await this.fetchResources();
242
+ });
243
+ return this.fetchResources();
244
+ }
245
+ async registerPrompts() {
246
+ if (!this.serverCapabilities || !this.serverCapabilities.prompts) return [];
247
+ if (this.serverCapabilities.prompts.listChanged) this.client.setNotificationHandler(PromptListChangedNotificationSchema, async (_notification) => {
248
+ this.prompts = await this.fetchPrompts();
249
+ });
250
+ return this.fetchPrompts();
251
+ }
252
+ async registerResourceTemplates() {
253
+ if (!this.serverCapabilities || !this.serverCapabilities.resources) return [];
254
+ return this.fetchResourceTemplates();
255
+ }
256
+ async fetchTools() {
257
+ let toolsAgg = [];
258
+ let toolsResult = { tools: [] };
259
+ do {
260
+ toolsResult = await this.client.listTools({ cursor: toolsResult.nextCursor }).catch(this._capabilityErrorHandler({ tools: [] }, "tools/list"));
261
+ toolsAgg = toolsAgg.concat(toolsResult.tools);
262
+ } while (toolsResult.nextCursor);
263
+ return toolsAgg;
264
+ }
265
+ async fetchResources() {
266
+ let resourcesAgg = [];
267
+ let resourcesResult = { resources: [] };
268
+ do {
269
+ resourcesResult = await this.client.listResources({ cursor: resourcesResult.nextCursor }).catch(this._capabilityErrorHandler({ resources: [] }, "resources/list"));
270
+ resourcesAgg = resourcesAgg.concat(resourcesResult.resources);
271
+ } while (resourcesResult.nextCursor);
272
+ return resourcesAgg;
273
+ }
274
+ async fetchPrompts() {
275
+ let promptsAgg = [];
276
+ let promptsResult = { prompts: [] };
277
+ do {
278
+ promptsResult = await this.client.listPrompts({ cursor: promptsResult.nextCursor }).catch(this._capabilityErrorHandler({ prompts: [] }, "prompts/list"));
279
+ promptsAgg = promptsAgg.concat(promptsResult.prompts);
280
+ } while (promptsResult.nextCursor);
281
+ return promptsAgg;
282
+ }
283
+ async fetchResourceTemplates() {
284
+ let templatesAgg = [];
285
+ let templatesResult = { resourceTemplates: [] };
286
+ do {
287
+ templatesResult = await this.client.listResourceTemplates({ cursor: templatesResult.nextCursor }).catch(this._capabilityErrorHandler({ resourceTemplates: [] }, "resources/templates/list"));
288
+ templatesAgg = templatesAgg.concat(templatesResult.resourceTemplates);
289
+ } while (templatesResult.nextCursor);
290
+ return templatesAgg;
291
+ }
292
+ /**
293
+ * Handle elicitation request from server
294
+ * Automatically uses the Agent's built-in elicitation handling if available
295
+ */
296
+ async handleElicitationRequest(_request) {
297
+ throw new Error("Elicitation handler must be implemented for your platform. Override handleElicitationRequest method.");
298
+ }
299
+ /**
300
+ * Get the transport for the client
301
+ * @param transportType - The transport type to get
302
+ * @returns The transport for the client
303
+ */
304
+ getTransport(transportType) {
305
+ switch (transportType) {
306
+ case "streamable-http": return new StreamableHTTPClientTransport(this.url, this.options.transport);
307
+ case "sse": return new SSEClientTransport(this.url, this.options.transport);
308
+ default: throw new Error(`Unsupported transport type: ${transportType}`);
309
+ }
310
+ }
311
+ async tryConnect(transportType) {
312
+ const transports = transportType === "auto" ? ["streamable-http", "sse"] : [transportType];
313
+ for (const currentTransportType of transports) {
314
+ const isLastTransport = currentTransportType === transports[transports.length - 1];
315
+ const hasFallback = transportType === "auto" && currentTransportType === "streamable-http" && !isLastTransport;
316
+ const transport = this.getTransport(currentTransportType);
317
+ try {
318
+ await this.client.connect(transport);
319
+ this.lastConnectedTransport = currentTransportType;
320
+ const url = this.url.toString();
321
+ this._onObservabilityEvent.fire({
322
+ type: "mcp:client:connect",
323
+ displayMessage: `Connected successfully using ${currentTransportType} transport for ${url}`,
324
+ payload: {
325
+ url,
326
+ transport: currentTransportType,
327
+ state: this.connectionState
328
+ },
329
+ timestamp: Date.now(),
330
+ id: nanoid()
331
+ });
332
+ break;
333
+ } catch (e) {
334
+ const error = e instanceof Error ? e : new Error(String(e));
335
+ if (isUnauthorized(error)) throw e;
336
+ if (hasFallback && isTransportNotImplemented(error)) {
337
+ const url = this.url.toString();
338
+ this._onObservabilityEvent.fire({
339
+ type: "mcp:client:connect",
340
+ displayMessage: `${currentTransportType} transport not available, trying ${transports[transports.indexOf(currentTransportType) + 1]} for ${url}`,
341
+ payload: {
342
+ url,
343
+ transport: currentTransportType,
344
+ state: this.connectionState
345
+ },
346
+ timestamp: Date.now(),
347
+ id: nanoid()
348
+ });
349
+ continue;
350
+ }
351
+ throw e;
352
+ }
353
+ }
354
+ this.client.setRequestHandler(ElicitRequestSchema, async (request) => {
355
+ return await this.handleElicitationRequest(request);
356
+ });
357
+ }
358
+ _capabilityErrorHandler(empty, method) {
359
+ return (e) => {
360
+ if (e.code === -32601) {
361
+ const url = this.url.toString();
362
+ this._onObservabilityEvent.fire({
363
+ type: "mcp:client:discover",
364
+ displayMessage: `The server advertised support for the capability ${method.split("/")[0]}, but returned "Method not found" for '${method}' for ${url}`,
365
+ payload: {
366
+ url,
367
+ capability: method.split("/")[0],
368
+ error: toErrorMessage(e)
369
+ },
370
+ timestamp: Date.now(),
371
+ id: nanoid()
372
+ });
373
+ return empty;
374
+ }
375
+ throw e;
376
+ };
377
+ }
378
+ };
379
+
380
+ //#endregion
381
+ //#region src/mcp/client.ts
382
+ const defaultClientOptions = { jsonSchemaValidator: new CfWorkerJsonSchemaValidator() };
383
+ /**
384
+ * Utility class that aggregates multiple MCP clients into one
385
+ */
386
+ var MCPClientManager = class {
387
+ /**
388
+ * @param _name Name of the MCP client
389
+ * @param _version Version of the MCP Client
390
+ * @param options Storage adapter for persisting MCP server state
391
+ */
392
+ constructor(_name, _version, options) {
393
+ this._name = _name;
394
+ this._version = _version;
395
+ this.mcpConnections = {};
396
+ this._didWarnAboutUnstableGetAITools = false;
397
+ this._connectionDisposables = /* @__PURE__ */ new Map();
398
+ this._isRestored = false;
399
+ this._onObservabilityEvent = new Emitter();
400
+ this.onObservabilityEvent = this._onObservabilityEvent.event;
401
+ this._onServerStateChanged = new Emitter();
402
+ this.onServerStateChanged = this._onServerStateChanged.event;
403
+ this._storage = options.storage;
404
+ }
405
+ /**
406
+ * Create an auth provider for a server
407
+ * @internal
408
+ */
409
+ createAuthProvider(serverId, callbackUrl, clientName, clientId) {
410
+ const authProvider = new DurableObjectOAuthClientProvider(this._storage, clientName, callbackUrl);
411
+ authProvider.serverId = serverId;
412
+ if (clientId) authProvider.clientId = clientId;
413
+ return authProvider;
414
+ }
415
+ /**
416
+ * Restore MCP server connections from storage
417
+ * This method is called on Agent initialization to restore previously connected servers
418
+ *
419
+ * @param clientName Name to use for OAuth client (typically the agent instance name)
420
+ */
421
+ async restoreConnectionsFromStorage(clientName) {
422
+ if (this._isRestored) return;
423
+ const servers = await this._storage.listServers();
424
+ if (!servers || servers.length === 0) {
425
+ this._isRestored = true;
426
+ return;
427
+ }
428
+ for (const server of servers) {
429
+ const existingConn = this.mcpConnections[server.id];
430
+ if (existingConn) {
431
+ if (existingConn.connectionState === "ready") {
432
+ console.warn(`[MCPClientManager] Server ${server.id} already has a ready connection. Skipping recreation.`);
433
+ continue;
434
+ }
435
+ if (existingConn.connectionState === "authenticating" || existingConn.connectionState === "connecting" || existingConn.connectionState === "discovering") continue;
436
+ if (existingConn.connectionState === "failed") {
437
+ try {
438
+ await existingConn.client.close();
439
+ } catch (error) {
440
+ console.warn(`[MCPClientManager] Error closing failed connection ${server.id}:`, error);
441
+ }
442
+ delete this.mcpConnections[server.id];
443
+ this._connectionDisposables.get(server.id)?.dispose();
444
+ this._connectionDisposables.delete(server.id);
445
+ }
446
+ }
447
+ const parsedOptions = server.server_options ? JSON.parse(server.server_options) : null;
448
+ const authProvider = this.createAuthProvider(server.id, server.callback_url, clientName, server.client_id ?? void 0);
449
+ this.createConnection(server.id, server.server_url, {
450
+ client: parsedOptions?.client ?? {},
451
+ transport: {
452
+ ...parsedOptions?.transport ?? {},
453
+ type: parsedOptions?.transport?.type ?? "auto",
454
+ authProvider
455
+ }
456
+ });
457
+ await this.connectToServer(server.id).catch((error) => {
458
+ console.error(`Error restoring ${server.id}:`, error);
459
+ });
460
+ }
461
+ this._isRestored = true;
462
+ }
463
+ /**
464
+ * Connect to and register an MCP server
465
+ *
466
+ * @deprecated This method is maintained for backward compatibility.
467
+ * For new code, use registerServer() and connectToServer() separately.
468
+ *
469
+ * @param url Server URL
470
+ * @param options Connection options
471
+ * @returns Object with server ID, auth URL (if OAuth), and client ID (if OAuth)
472
+ */
473
+ async connect(url, options = {}) {
474
+ /**
475
+ * We need to delay loading ai sdk, because putting it in module scope is
476
+ * causing issues with startup time.
477
+ * The only place it's used is in getAITools, which only matters after
478
+ * .connect() is called on at least one server.
479
+ * So it's safe to delay loading it until .connect() is called.
480
+ */
481
+ await this.ensureJsonSchema();
482
+ const id = options.reconnect?.id ?? nanoid(8);
483
+ if (options.transport?.authProvider) {
484
+ options.transport.authProvider.serverId = id;
485
+ if (options.reconnect?.oauthClientId) options.transport.authProvider.clientId = options.reconnect?.oauthClientId;
486
+ }
487
+ if (!options.reconnect?.oauthCode || !this.mcpConnections[id]) {
488
+ const normalizedTransport = {
489
+ ...options.transport,
490
+ type: options.transport?.type ?? "auto"
491
+ };
492
+ this.mcpConnections[id] = new MCPClientConnection(new URL(url), {
493
+ name: this._name,
494
+ version: this._version
495
+ }, {
496
+ client: options.client ?? {},
497
+ transport: normalizedTransport
498
+ });
499
+ const store = new DisposableStore();
500
+ const existing = this._connectionDisposables.get(id);
501
+ if (existing) existing.dispose();
502
+ this._connectionDisposables.set(id, store);
503
+ store.add(this.mcpConnections[id].onObservabilityEvent((event) => {
504
+ this._onObservabilityEvent.fire(event);
505
+ }));
506
+ }
507
+ await this.mcpConnections[id].init();
508
+ if (options.reconnect?.oauthCode) try {
509
+ await this.mcpConnections[id].completeAuthorization(options.reconnect.oauthCode);
510
+ await this.mcpConnections[id].establishConnection();
511
+ } catch (error) {
512
+ this._onObservabilityEvent.fire({
513
+ type: "mcp:client:connect",
514
+ displayMessage: `Failed to complete OAuth reconnection for ${id} for ${url}`,
515
+ payload: {
516
+ url,
517
+ transport: options.transport?.type ?? "auto",
518
+ state: this.mcpConnections[id].connectionState,
519
+ error: toErrorMessage(error)
520
+ },
521
+ timestamp: Date.now(),
522
+ id
523
+ });
524
+ throw error;
525
+ }
526
+ const authUrl = options.transport?.authProvider?.authUrl;
527
+ if (this.mcpConnections[id].connectionState === "authenticating" && authUrl && options.transport?.authProvider?.redirectUrl) return {
528
+ authUrl,
529
+ clientId: options.transport?.authProvider?.clientId,
530
+ id
531
+ };
532
+ return { id };
533
+ }
534
+ /**
535
+ * Create an in-memory connection object and set up observability
536
+ * Does NOT save to storage - use registerServer() for that
537
+ */
538
+ createConnection(id, url, options) {
539
+ if (this.mcpConnections[id]) return;
540
+ const normalizedTransport = {
541
+ ...options.transport,
542
+ type: options.transport?.type ?? "auto"
543
+ };
544
+ this.mcpConnections[id] = new MCPClientConnection(new URL(url), {
545
+ name: this._name,
546
+ version: this._version
547
+ }, {
548
+ client: {
549
+ ...defaultClientOptions,
550
+ ...options.client
551
+ },
552
+ transport: normalizedTransport
553
+ });
554
+ const store = new DisposableStore();
555
+ const existing = this._connectionDisposables.get(id);
556
+ if (existing) existing.dispose();
557
+ this._connectionDisposables.set(id, store);
558
+ store.add(this.mcpConnections[id].onObservabilityEvent((event) => {
559
+ this._onObservabilityEvent.fire(event);
560
+ }));
561
+ }
562
+ /**
563
+ * Register an MCP server connection without connecting
564
+ * Creates the connection object, sets up observability, and saves to storage
565
+ *
566
+ * @param id Server ID
567
+ * @param options Registration options including URL, name, callback URL, and connection config
568
+ * @returns Server ID
569
+ */
570
+ async registerServer(id, options) {
571
+ this.createConnection(id, options.url, {
572
+ client: options.client,
573
+ transport: {
574
+ ...options.transport,
575
+ type: options.transport?.type ?? "auto"
576
+ }
577
+ });
578
+ await this._storage.saveServer({
579
+ id,
580
+ name: options.name,
581
+ server_url: options.url,
582
+ callback_url: options.callbackUrl,
583
+ client_id: options.clientId ?? null,
584
+ auth_url: options.authUrl ?? null,
585
+ server_options: JSON.stringify({
586
+ client: options.client,
587
+ transport: options.transport
588
+ })
589
+ });
590
+ this._onServerStateChanged.fire();
591
+ return id;
592
+ }
593
+ /**
594
+ * Connect to an already registered MCP server and initialize the connection.
595
+ *
596
+ * For OAuth servers, this returns `{ state: "authenticating", authUrl, clientId? }`
597
+ * without establishing the connection. The user must complete the OAuth flow via
598
+ * the authUrl, which will trigger a callback handled by `handleCallbackRequest()`.
599
+ *
600
+ * For non-OAuth servers, this establishes the connection immediately and returns
601
+ * `{ state: "ready" }`.
602
+ *
603
+ * Updates storage with auth URL and client ID after connection.
604
+ *
605
+ * @param id Server ID (must be registered first via registerServer())
606
+ * @returns Connection result with current state and OAuth info (if applicable)
607
+ */
608
+ async connectToServer(id) {
609
+ const conn = this.mcpConnections[id];
610
+ if (!conn) throw new Error(`Server ${id} is not registered. Call registerServer() first.`);
611
+ await conn.init();
612
+ const authUrl = conn.options.transport.authProvider?.authUrl;
613
+ if (conn.connectionState === "authenticating" && authUrl && conn.options.transport.authProvider?.redirectUrl) {
614
+ const clientId = conn.options.transport.authProvider?.clientId;
615
+ const serverRow = (await this._storage.listServers()).find((s) => s.id === id);
616
+ if (serverRow) await this._storage.saveServer({
617
+ ...serverRow,
618
+ auth_url: authUrl,
619
+ client_id: clientId ?? null
620
+ });
621
+ this._onServerStateChanged.fire();
622
+ return {
623
+ state: "authenticating",
624
+ authUrl,
625
+ clientId
626
+ };
627
+ }
628
+ if (conn.connectionState === "ready") this._onServerStateChanged.fire();
629
+ return { state: "ready" };
630
+ }
631
+ async isCallbackRequest(req) {
632
+ if (req.method !== "GET") return false;
633
+ if (!req.url.includes("/callback")) return false;
634
+ return (await this._storage.listServers()).some((server) => server.callback_url && req.url.startsWith(server.callback_url));
635
+ }
636
+ async handleCallbackRequest(req) {
637
+ const url = new URL(req.url);
638
+ const matchingServer = (await this._storage.listServers()).find((server) => {
639
+ return server.callback_url && req.url.startsWith(server.callback_url);
640
+ });
641
+ if (!matchingServer) throw new Error(`No callback URI match found for the request url: ${req.url}. Was the request matched with \`isCallbackRequest()\`?`);
642
+ const serverId = matchingServer.id;
643
+ const code = url.searchParams.get("code");
644
+ const state = url.searchParams.get("state");
645
+ const error = url.searchParams.get("error");
646
+ const errorDescription = url.searchParams.get("error_description");
647
+ if (error) return {
648
+ serverId,
649
+ authSuccess: false,
650
+ authError: errorDescription || error
651
+ };
652
+ if (!code) throw new Error("Unauthorized: no code provided");
653
+ if (!state) throw new Error("Unauthorized: no state provided");
654
+ if (this.mcpConnections[serverId] === void 0) throw new Error(`Could not find serverId: ${serverId}`);
655
+ if (this.mcpConnections[serverId].connectionState === "ready") return {
656
+ serverId,
657
+ authSuccess: true
658
+ };
659
+ if (this.mcpConnections[serverId].connectionState !== "authenticating") throw new Error(`Failed to authenticate: the client is in "${this.mcpConnections[serverId].connectionState}" state, expected "authenticating"`);
660
+ const conn = this.mcpConnections[serverId];
661
+ if (!conn.options.transport.authProvider) throw new Error("Trying to finalize authentication for a server connection without an authProvider");
662
+ const clientId = conn.options.transport.authProvider.clientId || state;
663
+ conn.options.transport.authProvider.clientId = clientId;
664
+ conn.options.transport.authProvider.serverId = serverId;
665
+ try {
666
+ await conn.completeAuthorization(code);
667
+ await this._storage.clearAuthUrl(serverId);
668
+ this._onServerStateChanged.fire();
669
+ return {
670
+ serverId,
671
+ authSuccess: true
672
+ };
673
+ } catch (error$1) {
674
+ const errorMessage = error$1 instanceof Error ? error$1.message : String(error$1);
675
+ this._onServerStateChanged.fire();
676
+ return {
677
+ serverId,
678
+ authSuccess: false,
679
+ authError: errorMessage
680
+ };
681
+ }
682
+ }
683
+ /**
684
+ * Establish connection in the background after OAuth completion
685
+ * This method is called asynchronously and doesn't block the OAuth callback response
686
+ * @param serverId The server ID to establish connection for
687
+ */
688
+ async establishConnection(serverId) {
689
+ const conn = this.mcpConnections[serverId];
690
+ if (!conn) {
691
+ this._onObservabilityEvent.fire({
692
+ type: "mcp:client:preconnect",
693
+ displayMessage: `Connection not found for serverId: ${serverId}`,
694
+ payload: { serverId },
695
+ timestamp: Date.now(),
696
+ id: nanoid()
697
+ });
698
+ return;
699
+ }
700
+ try {
701
+ await conn.establishConnection();
702
+ this._onServerStateChanged.fire();
703
+ } catch (error) {
704
+ const url = conn.url.toString();
705
+ this._onObservabilityEvent.fire({
706
+ type: "mcp:client:connect",
707
+ displayMessage: `Failed to establish connection to server ${serverId} with url ${url}`,
708
+ payload: {
709
+ url,
710
+ transport: conn.options.transport.type ?? "auto",
711
+ state: conn.connectionState,
712
+ error: toErrorMessage(error)
713
+ },
714
+ timestamp: Date.now(),
715
+ id: nanoid()
716
+ });
717
+ this._onServerStateChanged.fire();
718
+ }
719
+ }
720
+ /**
721
+ * Configure OAuth callback handling
722
+ * @param config OAuth callback configuration
723
+ */
724
+ configureOAuthCallback(config) {
725
+ this._oauthCallbackConfig = config;
726
+ }
727
+ /**
728
+ * Get the current OAuth callback configuration
729
+ * @returns The current OAuth callback configuration
730
+ */
731
+ getOAuthCallbackConfig() {
732
+ return this._oauthCallbackConfig;
733
+ }
734
+ /**
735
+ * @returns namespaced list of tools
736
+ */
737
+ listTools() {
738
+ return getNamespacedData(this.mcpConnections, "tools");
739
+ }
740
+ /**
741
+ * Lazy-loads the jsonSchema function from the AI SDK.
742
+ *
743
+ * This defers importing the "ai" package until it's actually needed, which helps reduce
744
+ * initial bundle size and startup time. The jsonSchema function is required for converting
745
+ * MCP tools into AI SDK tool definitions via getAITools().
746
+ *
747
+ * @internal This method is for internal use only. It's automatically called before operations
748
+ * that need jsonSchema (like getAITools() or OAuth flows). External consumers should not need
749
+ * to call this directly.
750
+ */
751
+ async ensureJsonSchema() {
752
+ if (!this.jsonSchema) {
753
+ const { jsonSchema } = await import("ai");
754
+ this.jsonSchema = jsonSchema;
755
+ }
756
+ }
757
+ /**
758
+ * @returns a set of tools that you can use with the AI SDK
759
+ */
760
+ getAITools() {
761
+ if (!this.jsonSchema) throw new Error("jsonSchema not initialized.");
762
+ for (const [id, conn] of Object.entries(this.mcpConnections)) if (conn.connectionState !== "ready" && conn.connectionState !== "authenticating") console.warn(`[getAITools] WARNING: Reading tools from connection ${id} in state "${conn.connectionState}". Tools may not be loaded yet.`);
763
+ return Object.fromEntries(getNamespacedData(this.mcpConnections, "tools").map((tool) => {
764
+ return [`tool_${tool.serverId.replace(/-/g, "")}_${tool.name}`, {
765
+ description: tool.description,
766
+ execute: async (args) => {
767
+ const result = await this.callTool({
768
+ arguments: args,
769
+ name: tool.name,
770
+ serverId: tool.serverId
771
+ });
772
+ if (result.isError) throw new Error(result.content[0].text);
773
+ return result;
774
+ },
775
+ inputSchema: this.jsonSchema(tool.inputSchema),
776
+ outputSchema: tool.outputSchema ? this.jsonSchema(tool.outputSchema) : void 0
777
+ }];
778
+ }));
779
+ }
780
+ /**
781
+ * @deprecated this has been renamed to getAITools(), and unstable_getAITools will be removed in the next major version
782
+ * @returns a set of tools that you can use with the AI SDK
783
+ */
784
+ unstable_getAITools() {
785
+ if (!this._didWarnAboutUnstableGetAITools) {
786
+ this._didWarnAboutUnstableGetAITools = true;
787
+ console.warn("unstable_getAITools is deprecated, use getAITools instead. unstable_getAITools will be removed in the next major version.");
788
+ }
789
+ return this.getAITools();
790
+ }
791
+ /**
792
+ * Closes all connections to MCP servers
793
+ */
794
+ async closeAllConnections() {
795
+ const ids = Object.keys(this.mcpConnections);
796
+ await Promise.all(ids.map(async (id) => {
797
+ await this.mcpConnections[id].client.close();
798
+ }));
799
+ for (const id of ids) {
800
+ const store = this._connectionDisposables.get(id);
801
+ if (store) store.dispose();
802
+ this._connectionDisposables.delete(id);
803
+ delete this.mcpConnections[id];
804
+ }
805
+ }
806
+ /**
807
+ * Closes a connection to an MCP server
808
+ * @param id The id of the connection to close
809
+ */
810
+ async closeConnection(id) {
811
+ if (!this.mcpConnections[id]) throw new Error(`Connection with id "${id}" does not exist.`);
812
+ await this.mcpConnections[id].client.close();
813
+ delete this.mcpConnections[id];
814
+ const store = this._connectionDisposables.get(id);
815
+ if (store) store.dispose();
816
+ this._connectionDisposables.delete(id);
817
+ }
818
+ /**
819
+ * Remove an MCP server from storage
820
+ */
821
+ async removeServer(serverId) {
822
+ await this._storage.removeServer(serverId);
823
+ this._onServerStateChanged.fire();
824
+ }
825
+ /**
826
+ * List all MCP servers from storage
827
+ */
828
+ async listServers() {
829
+ return await this._storage.listServers();
830
+ }
831
+ /**
832
+ * Dispose the manager and all resources.
833
+ */
834
+ async dispose() {
835
+ try {
836
+ await this.closeAllConnections();
837
+ } finally {
838
+ this._onServerStateChanged.dispose();
839
+ this._onObservabilityEvent.dispose();
840
+ }
841
+ }
842
+ /**
843
+ * @returns namespaced list of prompts
844
+ */
845
+ listPrompts() {
846
+ return getNamespacedData(this.mcpConnections, "prompts");
847
+ }
848
+ /**
849
+ * @returns namespaced list of tools
850
+ */
851
+ listResources() {
852
+ return getNamespacedData(this.mcpConnections, "resources");
853
+ }
854
+ /**
855
+ * @returns namespaced list of resource templates
856
+ */
857
+ listResourceTemplates() {
858
+ return getNamespacedData(this.mcpConnections, "resourceTemplates");
859
+ }
860
+ /**
861
+ * Namespaced version of callTool
862
+ */
863
+ async callTool(params, resultSchema, options) {
864
+ const unqualifiedName = params.name.replace(`${params.serverId}.`, "");
865
+ return this.mcpConnections[params.serverId].client.callTool({
866
+ ...params,
867
+ name: unqualifiedName
868
+ }, resultSchema, options);
869
+ }
870
+ /**
871
+ * Namespaced version of readResource
872
+ */
873
+ readResource(params, options) {
874
+ return this.mcpConnections[params.serverId].client.readResource(params, options);
875
+ }
876
+ /**
877
+ * Namespaced version of getPrompt
878
+ */
879
+ getPrompt(params, options) {
880
+ return this.mcpConnections[params.serverId].client.getPrompt(params, options);
881
+ }
882
+ };
883
+ function getNamespacedData(mcpClients, type) {
884
+ return Object.entries(mcpClients).map(([name, conn]) => {
885
+ return {
886
+ data: conn[type],
887
+ name
888
+ };
889
+ }).flatMap(({ name: serverId, data }) => {
890
+ return data.map((item) => {
891
+ return {
892
+ ...item,
893
+ serverId
894
+ };
895
+ });
896
+ });
897
+ }
898
+
899
+ //#endregion
900
+ export { getNamespacedData as n, DisposableStore as r, MCPClientManager as t };
901
+ //# sourceMappingURL=client-DpkZyXgJ.js.map