agents 0.2.23 → 0.2.25

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 (58) hide show
  1. package/README.md +5 -3
  2. package/dist/ai-chat-agent.d.ts +86 -13
  3. package/dist/ai-chat-agent.js +340 -74
  4. package/dist/ai-chat-agent.js.map +1 -1
  5. package/dist/{ai-chat-v5-migration-DBHGW4Hv.js → ai-chat-v5-migration-BSiGZmYU.js} +1 -1
  6. package/dist/{ai-chat-v5-migration-DBHGW4Hv.js.map → ai-chat-v5-migration-BSiGZmYU.js.map} +1 -1
  7. package/dist/ai-chat-v5-migration.js +1 -1
  8. package/dist/ai-react.d.ts +14 -9
  9. package/dist/ai-react.js +179 -29
  10. package/dist/ai-react.js.map +1 -1
  11. package/dist/{ai-types-D5YoPrBZ.d.ts → ai-types-81H_-Uxh.d.ts} +15 -7
  12. package/dist/{ai-types-B3aQaFv3.js → ai-types-CrMqkwc_.js} +5 -1
  13. package/dist/ai-types-CrMqkwc_.js.map +1 -0
  14. package/dist/ai-types.d.ts +1 -1
  15. package/dist/ai-types.js +1 -1
  16. package/dist/{client-BfiZ3HQd.js → client-B3SR12TQ.js} +2 -2
  17. package/dist/{client-BfiZ3HQd.js.map → client-B3SR12TQ.js.map} +1 -1
  18. package/dist/{client-CbWe9FBd.d.ts → client-BAQA84dr.d.ts} +2 -2
  19. package/dist/client-BZq9qau2.js +1093 -0
  20. package/dist/client-BZq9qau2.js.map +1 -0
  21. package/dist/client-CsaP9Irq.d.ts +1528 -0
  22. package/dist/client.d.ts +2 -2
  23. package/dist/client.js +2 -2
  24. package/dist/codemode/ai.js +5 -5
  25. package/dist/{do-oauth-client-provider-DGc5pP0l.d.ts → do-oauth-client-provider-C2CHH5x-.d.ts} +1 -1
  26. package/dist/{do-oauth-client-provider-CswoD5Lu.js → do-oauth-client-provider-CwqK5SXm.js} +2 -1
  27. package/dist/do-oauth-client-provider-CwqK5SXm.js.map +1 -0
  28. package/dist/{index-DhJCaDWd.d.ts → index-BUle9RiP.d.ts} +2 -2
  29. package/dist/{index-DEZFuVoU.d.ts → index-Bx5KK3VJ.d.ts} +44 -23
  30. package/dist/index.d.ts +6 -6
  31. package/dist/index.js +5 -5
  32. package/dist/mcp/client.d.ts +4 -4
  33. package/dist/mcp/client.js +2 -1
  34. package/dist/mcp/do-oauth-client-provider.d.ts +1 -1
  35. package/dist/mcp/do-oauth-client-provider.js +1 -1
  36. package/dist/mcp/index.d.ts +11 -11
  37. package/dist/mcp/index.js +21 -14
  38. package/dist/mcp/index.js.map +1 -1
  39. package/dist/mcp/x402.js +10 -6
  40. package/dist/mcp/x402.js.map +1 -1
  41. package/dist/{mcp-Dw5vDrY8.d.ts → mcp-BwPscEiF.d.ts} +1 -1
  42. package/dist/observability/index.d.ts +2 -2
  43. package/dist/observability/index.js +5 -5
  44. package/dist/{react-CrV9uP64.d.ts → react-CbwD4fBf.d.ts} +4 -4
  45. package/dist/react.d.ts +9 -9
  46. package/dist/react.js +2 -2
  47. package/dist/react.js.map +1 -1
  48. package/dist/{serializable-CymX8ovI.d.ts → serializable-faDkMCai.d.ts} +1 -1
  49. package/dist/serializable.d.ts +1 -1
  50. package/dist/{src-C8K3lu37.js → src-D_KKH_4c.js} +99 -146
  51. package/dist/src-D_KKH_4c.js.map +1 -0
  52. package/package.json +7 -7
  53. package/dist/ai-types-B3aQaFv3.js.map +0 -1
  54. package/dist/client-DZhjV_XA.js +0 -719
  55. package/dist/client-DZhjV_XA.js.map +0 -1
  56. package/dist/client-GfgZTqrS.d.ts +0 -5283
  57. package/dist/do-oauth-client-provider-CswoD5Lu.js.map +0 -1
  58. package/dist/src-C8K3lu37.js.map +0 -1
@@ -0,0 +1,1093 @@
1
+ import { t as DurableObjectOAuthClientProvider } from "./do-oauth-client-provider-CwqK5SXm.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
+ /**
64
+ * Connection state machine for MCP client connections.
65
+ *
66
+ * State transitions:
67
+ * - Non-OAuth: init() → CONNECTING → DISCOVERING → READY
68
+ * - OAuth: init() → AUTHENTICATING → (callback) → CONNECTING → DISCOVERING → READY
69
+ * - Any state can transition to FAILED on error
70
+ */
71
+ const MCPConnectionState = {
72
+ AUTHENTICATING: "authenticating",
73
+ CONNECTING: "connecting",
74
+ CONNECTED: "connected",
75
+ DISCOVERING: "discovering",
76
+ READY: "ready",
77
+ FAILED: "failed"
78
+ };
79
+ var MCPClientConnection = class {
80
+ constructor(url, info, options = {
81
+ client: {},
82
+ transport: {}
83
+ }) {
84
+ this.url = url;
85
+ this.options = options;
86
+ this.connectionState = MCPConnectionState.CONNECTING;
87
+ this.tools = [];
88
+ this.prompts = [];
89
+ this.resources = [];
90
+ this.resourceTemplates = [];
91
+ this._onObservabilityEvent = new Emitter();
92
+ this.onObservabilityEvent = this._onObservabilityEvent.event;
93
+ this.client = new Client(info, {
94
+ ...options.client,
95
+ capabilities: {
96
+ ...options.client?.capabilities,
97
+ elicitation: {}
98
+ }
99
+ });
100
+ }
101
+ /**
102
+ * Initialize a client connection, if authentication is required, the connection will be in the AUTHENTICATING state
103
+ * Sets connection state based on the result and emits observability events
104
+ *
105
+ * @returns Error message if connection failed, undefined otherwise
106
+ */
107
+ async init() {
108
+ const transportType = this.options.transport.type;
109
+ if (!transportType) throw new Error("Transport type must be specified");
110
+ const res = await this.tryConnect(transportType);
111
+ this.connectionState = res.state;
112
+ if (res.state === MCPConnectionState.CONNECTED && res.transport) {
113
+ this.client.setRequestHandler(ElicitRequestSchema, async (request) => {
114
+ return await this.handleElicitationRequest(request);
115
+ });
116
+ this.lastConnectedTransport = res.transport;
117
+ this._onObservabilityEvent.fire({
118
+ type: "mcp:client:connect",
119
+ displayMessage: `Connected successfully using ${res.transport} transport for ${this.url.toString()}`,
120
+ payload: {
121
+ url: this.url.toString(),
122
+ transport: res.transport,
123
+ state: this.connectionState
124
+ },
125
+ timestamp: Date.now(),
126
+ id: nanoid()
127
+ });
128
+ return;
129
+ } else if (res.state === MCPConnectionState.FAILED && res.error) {
130
+ const errorMessage = toErrorMessage(res.error);
131
+ this._onObservabilityEvent.fire({
132
+ type: "mcp:client:connect",
133
+ displayMessage: `Failed to connect to ${this.url.toString()}: ${errorMessage}`,
134
+ payload: {
135
+ url: this.url.toString(),
136
+ transport: transportType,
137
+ state: this.connectionState,
138
+ error: errorMessage
139
+ },
140
+ timestamp: Date.now(),
141
+ id: nanoid()
142
+ });
143
+ return errorMessage;
144
+ }
145
+ }
146
+ /**
147
+ * Finish OAuth by probing transports based on configured type.
148
+ * - Explicit: finish on that transport
149
+ * - Auto: try streamable-http, then sse on 404/405/Not Implemented
150
+ */
151
+ async finishAuthProbe(code) {
152
+ if (!this.options.transport.authProvider) throw new Error("No auth provider configured");
153
+ const configuredType = this.options.transport.type;
154
+ if (!configuredType) throw new Error("Transport type must be specified");
155
+ const finishAuth = async (base) => {
156
+ await this.getTransport(base).finishAuth(code);
157
+ };
158
+ if (configuredType === "sse" || configuredType === "streamable-http") {
159
+ await finishAuth(configuredType);
160
+ return;
161
+ }
162
+ try {
163
+ await finishAuth("streamable-http");
164
+ } catch (e) {
165
+ if (isTransportNotImplemented(e)) {
166
+ await finishAuth("sse");
167
+ return;
168
+ }
169
+ throw e;
170
+ }
171
+ }
172
+ /**
173
+ * Complete OAuth authorization
174
+ */
175
+ async completeAuthorization(code) {
176
+ if (this.connectionState !== MCPConnectionState.AUTHENTICATING) throw new Error("Connection must be in authenticating state to complete authorization");
177
+ try {
178
+ await this.finishAuthProbe(code);
179
+ this.connectionState = MCPConnectionState.CONNECTING;
180
+ } catch (error) {
181
+ this.connectionState = MCPConnectionState.FAILED;
182
+ throw error;
183
+ }
184
+ }
185
+ /**
186
+ * Discover server capabilities and register tools, resources, prompts, and templates.
187
+ * This method does the work but does not manage connection state - that's handled by discover().
188
+ */
189
+ async discoverAndRegister() {
190
+ this.serverCapabilities = this.client.getServerCapabilities();
191
+ if (!this.serverCapabilities) throw new Error("The MCP Server failed to return server capabilities");
192
+ const operations = [];
193
+ const operationNames = [];
194
+ operations.push(Promise.resolve(this.client.getInstructions()));
195
+ operationNames.push("instructions");
196
+ if (this.serverCapabilities.tools) {
197
+ operations.push(this.registerTools());
198
+ operationNames.push("tools");
199
+ }
200
+ if (this.serverCapabilities.resources) {
201
+ operations.push(this.registerResources());
202
+ operationNames.push("resources");
203
+ }
204
+ if (this.serverCapabilities.prompts) {
205
+ operations.push(this.registerPrompts());
206
+ operationNames.push("prompts");
207
+ }
208
+ if (this.serverCapabilities.resources) {
209
+ operations.push(this.registerResourceTemplates());
210
+ operationNames.push("resource templates");
211
+ }
212
+ try {
213
+ const results = await Promise.all(operations);
214
+ for (let i = 0; i < results.length; i++) {
215
+ const result = results[i];
216
+ switch (operationNames[i]) {
217
+ case "instructions":
218
+ this.instructions = result;
219
+ break;
220
+ case "tools":
221
+ this.tools = result;
222
+ break;
223
+ case "resources":
224
+ this.resources = result;
225
+ break;
226
+ case "prompts":
227
+ this.prompts = result;
228
+ break;
229
+ case "resource templates":
230
+ this.resourceTemplates = result;
231
+ break;
232
+ }
233
+ }
234
+ } catch (error) {
235
+ this._onObservabilityEvent.fire({
236
+ type: "mcp:client:discover",
237
+ displayMessage: `Failed to discover capabilities for ${this.url.toString()}: ${toErrorMessage(error)}`,
238
+ payload: {
239
+ url: this.url.toString(),
240
+ error: toErrorMessage(error)
241
+ },
242
+ timestamp: Date.now(),
243
+ id: nanoid()
244
+ });
245
+ throw error;
246
+ }
247
+ }
248
+ /**
249
+ * Discover server capabilities with timeout and cancellation support.
250
+ * If called while a previous discovery is in-flight, the previous discovery will be aborted.
251
+ *
252
+ * @param options Optional configuration
253
+ * @param options.timeoutMs Timeout in milliseconds (default: 15000)
254
+ * @returns Result indicating success/failure with optional error message
255
+ */
256
+ async discover(options = {}) {
257
+ const { timeoutMs = 15e3 } = options;
258
+ if (this.connectionState !== MCPConnectionState.CONNECTED && this.connectionState !== MCPConnectionState.READY) {
259
+ this._onObservabilityEvent.fire({
260
+ type: "mcp:client:discover",
261
+ displayMessage: `Discovery skipped for ${this.url.toString()}, state is ${this.connectionState}`,
262
+ payload: {
263
+ url: this.url.toString(),
264
+ state: this.connectionState
265
+ },
266
+ timestamp: Date.now(),
267
+ id: nanoid()
268
+ });
269
+ return {
270
+ success: false,
271
+ error: `Discovery skipped - connection in ${this.connectionState} state`
272
+ };
273
+ }
274
+ if (this._discoveryAbortController) {
275
+ this._discoveryAbortController.abort();
276
+ this._discoveryAbortController = void 0;
277
+ }
278
+ const abortController = new AbortController();
279
+ this._discoveryAbortController = abortController;
280
+ this.connectionState = MCPConnectionState.DISCOVERING;
281
+ let timeoutId;
282
+ try {
283
+ const timeoutPromise = new Promise((_, reject) => {
284
+ timeoutId = setTimeout(() => reject(/* @__PURE__ */ new Error(`Discovery timed out after ${timeoutMs}ms`)), timeoutMs);
285
+ });
286
+ if (abortController.signal.aborted) throw new Error("Discovery was cancelled");
287
+ const abortPromise = new Promise((_, reject) => {
288
+ abortController.signal.addEventListener("abort", () => {
289
+ reject(/* @__PURE__ */ new Error("Discovery was cancelled"));
290
+ });
291
+ });
292
+ await Promise.race([
293
+ this.discoverAndRegister(),
294
+ timeoutPromise,
295
+ abortPromise
296
+ ]);
297
+ if (timeoutId !== void 0) clearTimeout(timeoutId);
298
+ this.connectionState = MCPConnectionState.READY;
299
+ this._onObservabilityEvent.fire({
300
+ type: "mcp:client:discover",
301
+ displayMessage: `Discovery completed for ${this.url.toString()}`,
302
+ payload: { url: this.url.toString() },
303
+ timestamp: Date.now(),
304
+ id: nanoid()
305
+ });
306
+ return { success: true };
307
+ } catch (e) {
308
+ if (timeoutId !== void 0) clearTimeout(timeoutId);
309
+ this.connectionState = MCPConnectionState.CONNECTED;
310
+ return {
311
+ success: false,
312
+ error: e instanceof Error ? e.message : String(e)
313
+ };
314
+ } finally {
315
+ this._discoveryAbortController = void 0;
316
+ }
317
+ }
318
+ /**
319
+ * Cancel any in-flight discovery operation.
320
+ * Called when closing the connection.
321
+ */
322
+ cancelDiscovery() {
323
+ if (this._discoveryAbortController) {
324
+ this._discoveryAbortController.abort();
325
+ this._discoveryAbortController = void 0;
326
+ }
327
+ }
328
+ /**
329
+ * Notification handler registration for tools
330
+ * Should only be called if serverCapabilities.tools exists
331
+ */
332
+ async registerTools() {
333
+ if (this.serverCapabilities?.tools?.listChanged) this.client.setNotificationHandler(ToolListChangedNotificationSchema, async (_notification) => {
334
+ this.tools = await this.fetchTools();
335
+ });
336
+ return this.fetchTools();
337
+ }
338
+ /**
339
+ * Notification handler registration for resources
340
+ * Should only be called if serverCapabilities.resources exists
341
+ */
342
+ async registerResources() {
343
+ if (this.serverCapabilities?.resources?.listChanged) this.client.setNotificationHandler(ResourceListChangedNotificationSchema, async (_notification) => {
344
+ this.resources = await this.fetchResources();
345
+ });
346
+ return this.fetchResources();
347
+ }
348
+ /**
349
+ * Notification handler registration for prompts
350
+ * Should only be called if serverCapabilities.prompts exists
351
+ */
352
+ async registerPrompts() {
353
+ if (this.serverCapabilities?.prompts?.listChanged) this.client.setNotificationHandler(PromptListChangedNotificationSchema, async (_notification) => {
354
+ this.prompts = await this.fetchPrompts();
355
+ });
356
+ return this.fetchPrompts();
357
+ }
358
+ async registerResourceTemplates() {
359
+ return this.fetchResourceTemplates();
360
+ }
361
+ async fetchTools() {
362
+ let toolsAgg = [];
363
+ let toolsResult = { tools: [] };
364
+ do {
365
+ toolsResult = await this.client.listTools({ cursor: toolsResult.nextCursor }).catch(this._capabilityErrorHandler({ tools: [] }, "tools/list"));
366
+ toolsAgg = toolsAgg.concat(toolsResult.tools);
367
+ } while (toolsResult.nextCursor);
368
+ return toolsAgg;
369
+ }
370
+ async fetchResources() {
371
+ let resourcesAgg = [];
372
+ let resourcesResult = { resources: [] };
373
+ do {
374
+ resourcesResult = await this.client.listResources({ cursor: resourcesResult.nextCursor }).catch(this._capabilityErrorHandler({ resources: [] }, "resources/list"));
375
+ resourcesAgg = resourcesAgg.concat(resourcesResult.resources);
376
+ } while (resourcesResult.nextCursor);
377
+ return resourcesAgg;
378
+ }
379
+ async fetchPrompts() {
380
+ let promptsAgg = [];
381
+ let promptsResult = { prompts: [] };
382
+ do {
383
+ promptsResult = await this.client.listPrompts({ cursor: promptsResult.nextCursor }).catch(this._capabilityErrorHandler({ prompts: [] }, "prompts/list"));
384
+ promptsAgg = promptsAgg.concat(promptsResult.prompts);
385
+ } while (promptsResult.nextCursor);
386
+ return promptsAgg;
387
+ }
388
+ async fetchResourceTemplates() {
389
+ let templatesAgg = [];
390
+ let templatesResult = { resourceTemplates: [] };
391
+ do {
392
+ templatesResult = await this.client.listResourceTemplates({ cursor: templatesResult.nextCursor }).catch(this._capabilityErrorHandler({ resourceTemplates: [] }, "resources/templates/list"));
393
+ templatesAgg = templatesAgg.concat(templatesResult.resourceTemplates);
394
+ } while (templatesResult.nextCursor);
395
+ return templatesAgg;
396
+ }
397
+ /**
398
+ * Handle elicitation request from server
399
+ * Automatically uses the Agent's built-in elicitation handling if available
400
+ */
401
+ async handleElicitationRequest(_request) {
402
+ throw new Error("Elicitation handler must be implemented for your platform. Override handleElicitationRequest method.");
403
+ }
404
+ /**
405
+ * Get the transport for the client
406
+ * @param transportType - The transport type to get
407
+ * @returns The transport for the client
408
+ */
409
+ getTransport(transportType) {
410
+ switch (transportType) {
411
+ case "streamable-http": return new StreamableHTTPClientTransport(this.url, this.options.transport);
412
+ case "sse": return new SSEClientTransport(this.url, this.options.transport);
413
+ default: throw new Error(`Unsupported transport type: ${transportType}`);
414
+ }
415
+ }
416
+ async tryConnect(transportType) {
417
+ const transports = transportType === "auto" ? ["streamable-http", "sse"] : [transportType];
418
+ for (const currentTransportType of transports) {
419
+ const isLastTransport = currentTransportType === transports[transports.length - 1];
420
+ const hasFallback = transportType === "auto" && currentTransportType === "streamable-http" && !isLastTransport;
421
+ const transport = this.getTransport(currentTransportType);
422
+ try {
423
+ await this.client.connect(transport);
424
+ return {
425
+ state: MCPConnectionState.CONNECTED,
426
+ transport: currentTransportType
427
+ };
428
+ } catch (e) {
429
+ const error = e instanceof Error ? e : new Error(String(e));
430
+ if (isUnauthorized(error)) return { state: MCPConnectionState.AUTHENTICATING };
431
+ if (isTransportNotImplemented(error) && hasFallback) continue;
432
+ return {
433
+ state: MCPConnectionState.FAILED,
434
+ error
435
+ };
436
+ }
437
+ }
438
+ return {
439
+ state: MCPConnectionState.FAILED,
440
+ error: /* @__PURE__ */ new Error("No transports available")
441
+ };
442
+ }
443
+ _capabilityErrorHandler(empty, method) {
444
+ return (e) => {
445
+ if (e.code === -32601) {
446
+ const url = this.url.toString();
447
+ this._onObservabilityEvent.fire({
448
+ type: "mcp:client:discover",
449
+ displayMessage: `The server advertised support for the capability ${method.split("/")[0]}, but returned "Method not found" for '${method}' for ${url}`,
450
+ payload: {
451
+ url,
452
+ capability: method.split("/")[0],
453
+ error: toErrorMessage(e)
454
+ },
455
+ timestamp: Date.now(),
456
+ id: nanoid()
457
+ });
458
+ return empty;
459
+ }
460
+ throw e;
461
+ };
462
+ }
463
+ };
464
+
465
+ //#endregion
466
+ //#region src/mcp/client.ts
467
+ const defaultClientOptions = { jsonSchemaValidator: new CfWorkerJsonSchemaValidator() };
468
+ /**
469
+ * Utility class that aggregates multiple MCP clients into one
470
+ */
471
+ var MCPClientManager = class {
472
+ /**
473
+ * @param _name Name of the MCP client
474
+ * @param _version Version of the MCP Client
475
+ * @param options Storage adapter for persisting MCP server state
476
+ */
477
+ constructor(_name, _version, options) {
478
+ this._name = _name;
479
+ this._version = _version;
480
+ this.mcpConnections = {};
481
+ this._didWarnAboutUnstableGetAITools = false;
482
+ this._connectionDisposables = /* @__PURE__ */ new Map();
483
+ this._isRestored = false;
484
+ this._onObservabilityEvent = new Emitter();
485
+ this.onObservabilityEvent = this._onObservabilityEvent.event;
486
+ this._onServerStateChanged = new Emitter();
487
+ this.onServerStateChanged = this._onServerStateChanged.event;
488
+ if (!options.storage) throw new Error("MCPClientManager requires a valid DurableObjectStorage instance");
489
+ this._storage = options.storage;
490
+ }
491
+ sql(query, ...bindings) {
492
+ return [...this._storage.sql.exec(query, ...bindings)];
493
+ }
494
+ saveServerToStorage(server) {
495
+ this.sql(`INSERT OR REPLACE INTO cf_agents_mcp_servers (
496
+ id, name, server_url, client_id, auth_url, callback_url, server_options
497
+ ) VALUES (?, ?, ?, ?, ?, ?, ?)`, server.id, server.name, server.server_url, server.client_id ?? null, server.auth_url ?? null, server.callback_url, server.server_options ?? null);
498
+ }
499
+ removeServerFromStorage(serverId) {
500
+ this.sql("DELETE FROM cf_agents_mcp_servers WHERE id = ?", serverId);
501
+ }
502
+ getServersFromStorage() {
503
+ return this.sql("SELECT id, name, server_url, client_id, auth_url, callback_url, server_options FROM cf_agents_mcp_servers");
504
+ }
505
+ clearServerAuthUrl(serverId) {
506
+ this.sql("UPDATE cf_agents_mcp_servers SET auth_url = NULL WHERE id = ?", serverId);
507
+ }
508
+ /**
509
+ * Create an auth provider for a server
510
+ * @internal
511
+ */
512
+ createAuthProvider(serverId, callbackUrl, clientName, clientId) {
513
+ if (!this._storage) throw new Error("Cannot create auth provider: storage is not initialized");
514
+ const authProvider = new DurableObjectOAuthClientProvider(this._storage, clientName, callbackUrl);
515
+ authProvider.serverId = serverId;
516
+ if (clientId) authProvider.clientId = clientId;
517
+ return authProvider;
518
+ }
519
+ /**
520
+ * Restore MCP server connections from storage
521
+ * This method is called on Agent initialization to restore previously connected servers
522
+ *
523
+ * @param clientName Name to use for OAuth client (typically the agent instance name)
524
+ */
525
+ async restoreConnectionsFromStorage(clientName) {
526
+ if (this._isRestored) return;
527
+ const servers = this.getServersFromStorage();
528
+ if (!servers || servers.length === 0) {
529
+ this._isRestored = true;
530
+ return;
531
+ }
532
+ for (const server of servers) {
533
+ const existingConn = this.mcpConnections[server.id];
534
+ if (existingConn) {
535
+ if (existingConn.connectionState === MCPConnectionState.READY) {
536
+ console.warn(`[MCPClientManager] Server ${server.id} already has a ready connection. Skipping recreation.`);
537
+ continue;
538
+ }
539
+ if (existingConn.connectionState === MCPConnectionState.AUTHENTICATING || existingConn.connectionState === MCPConnectionState.CONNECTING || existingConn.connectionState === MCPConnectionState.DISCOVERING) continue;
540
+ if (existingConn.connectionState === MCPConnectionState.FAILED) {
541
+ try {
542
+ await existingConn.client.close();
543
+ } catch (error) {
544
+ console.warn(`[MCPClientManager] Error closing failed connection ${server.id}:`, error);
545
+ }
546
+ delete this.mcpConnections[server.id];
547
+ this._connectionDisposables.get(server.id)?.dispose();
548
+ this._connectionDisposables.delete(server.id);
549
+ }
550
+ }
551
+ const parsedOptions = server.server_options ? JSON.parse(server.server_options) : null;
552
+ const authProvider = this.createAuthProvider(server.id, server.callback_url, clientName, server.client_id ?? void 0);
553
+ const conn = this.createConnection(server.id, server.server_url, {
554
+ client: parsedOptions?.client ?? {},
555
+ transport: {
556
+ ...parsedOptions?.transport ?? {},
557
+ type: parsedOptions?.transport?.type ?? "auto",
558
+ authProvider
559
+ }
560
+ });
561
+ if (server.auth_url) {
562
+ conn.connectionState = MCPConnectionState.AUTHENTICATING;
563
+ continue;
564
+ }
565
+ this._restoreServer(server.id);
566
+ }
567
+ this._isRestored = true;
568
+ }
569
+ /**
570
+ * Internal method to restore a single server connection and discovery
571
+ */
572
+ async _restoreServer(serverId) {
573
+ if ((await this.connectToServer(serverId).catch((error) => {
574
+ console.error(`Error connecting to ${serverId}:`, error);
575
+ return null;
576
+ }))?.state === MCPConnectionState.CONNECTED) {
577
+ const discoverResult = await this.discoverIfConnected(serverId);
578
+ if (discoverResult && !discoverResult.success) console.error(`Error discovering ${serverId}:`, discoverResult.error);
579
+ }
580
+ }
581
+ /**
582
+ * Connect to and register an MCP server
583
+ *
584
+ * @deprecated This method is maintained for backward compatibility.
585
+ * For new code, use registerServer() and connectToServer() separately.
586
+ *
587
+ * @param url Server URL
588
+ * @param options Connection options
589
+ * @returns Object with server ID, auth URL (if OAuth), and client ID (if OAuth)
590
+ */
591
+ async connect(url, options = {}) {
592
+ /**
593
+ * We need to delay loading ai sdk, because putting it in module scope is
594
+ * causing issues with startup time.
595
+ * The only place it's used is in getAITools, which only matters after
596
+ * .connect() is called on at least one server.
597
+ * So it's safe to delay loading it until .connect() is called.
598
+ */
599
+ await this.ensureJsonSchema();
600
+ const id = options.reconnect?.id ?? nanoid(8);
601
+ if (options.transport?.authProvider) {
602
+ options.transport.authProvider.serverId = id;
603
+ if (options.reconnect?.oauthClientId) options.transport.authProvider.clientId = options.reconnect?.oauthClientId;
604
+ }
605
+ if (!options.reconnect?.oauthCode || !this.mcpConnections[id]) {
606
+ const normalizedTransport = {
607
+ ...options.transport,
608
+ type: options.transport?.type ?? "auto"
609
+ };
610
+ this.mcpConnections[id] = new MCPClientConnection(new URL(url), {
611
+ name: this._name,
612
+ version: this._version
613
+ }, {
614
+ client: options.client ?? {},
615
+ transport: normalizedTransport
616
+ });
617
+ const store = new DisposableStore();
618
+ const existing = this._connectionDisposables.get(id);
619
+ if (existing) existing.dispose();
620
+ this._connectionDisposables.set(id, store);
621
+ store.add(this.mcpConnections[id].onObservabilityEvent((event) => {
622
+ this._onObservabilityEvent.fire(event);
623
+ }));
624
+ }
625
+ await this.mcpConnections[id].init();
626
+ if (options.reconnect?.oauthCode) try {
627
+ await this.mcpConnections[id].completeAuthorization(options.reconnect.oauthCode);
628
+ await this.mcpConnections[id].init();
629
+ } catch (error) {
630
+ this._onObservabilityEvent.fire({
631
+ type: "mcp:client:connect",
632
+ displayMessage: `Failed to complete OAuth reconnection for ${id} for ${url}`,
633
+ payload: {
634
+ url,
635
+ transport: options.transport?.type ?? "auto",
636
+ state: this.mcpConnections[id].connectionState,
637
+ error: toErrorMessage(error)
638
+ },
639
+ timestamp: Date.now(),
640
+ id
641
+ });
642
+ throw error;
643
+ }
644
+ const authUrl = options.transport?.authProvider?.authUrl;
645
+ if (this.mcpConnections[id].connectionState === MCPConnectionState.AUTHENTICATING && authUrl && options.transport?.authProvider?.redirectUrl) return {
646
+ authUrl,
647
+ clientId: options.transport?.authProvider?.clientId,
648
+ id
649
+ };
650
+ const discoverResult = await this.discoverIfConnected(id);
651
+ if (discoverResult && !discoverResult.success) throw new Error(`Failed to discover server capabilities: ${discoverResult.error}`);
652
+ return { id };
653
+ }
654
+ /**
655
+ * Create an in-memory connection object and set up observability
656
+ * Does NOT save to storage - use registerServer() for that
657
+ * @returns The connection object (existing or newly created)
658
+ */
659
+ createConnection(id, url, options) {
660
+ if (this.mcpConnections[id]) return this.mcpConnections[id];
661
+ const normalizedTransport = {
662
+ ...options.transport,
663
+ type: options.transport?.type ?? "auto"
664
+ };
665
+ this.mcpConnections[id] = new MCPClientConnection(new URL(url), {
666
+ name: this._name,
667
+ version: this._version
668
+ }, {
669
+ client: {
670
+ ...defaultClientOptions,
671
+ ...options.client
672
+ },
673
+ transport: normalizedTransport
674
+ });
675
+ const store = new DisposableStore();
676
+ const existing = this._connectionDisposables.get(id);
677
+ if (existing) existing.dispose();
678
+ this._connectionDisposables.set(id, store);
679
+ store.add(this.mcpConnections[id].onObservabilityEvent((event) => {
680
+ this._onObservabilityEvent.fire(event);
681
+ }));
682
+ return this.mcpConnections[id];
683
+ }
684
+ /**
685
+ * Register an MCP server connection without connecting
686
+ * Creates the connection object, sets up observability, and saves to storage
687
+ *
688
+ * @param id Server ID
689
+ * @param options Registration options including URL, name, callback URL, and connection config
690
+ * @returns Server ID
691
+ */
692
+ async registerServer(id, options) {
693
+ this.createConnection(id, options.url, {
694
+ client: options.client,
695
+ transport: {
696
+ ...options.transport,
697
+ type: options.transport?.type ?? "auto"
698
+ }
699
+ });
700
+ const { authProvider: _, ...transportWithoutAuth } = options.transport ?? {};
701
+ this.saveServerToStorage({
702
+ id,
703
+ name: options.name,
704
+ server_url: options.url,
705
+ callback_url: options.callbackUrl,
706
+ client_id: options.clientId ?? null,
707
+ auth_url: options.authUrl ?? null,
708
+ server_options: JSON.stringify({
709
+ client: options.client,
710
+ transport: transportWithoutAuth
711
+ })
712
+ });
713
+ this._onServerStateChanged.fire();
714
+ return id;
715
+ }
716
+ /**
717
+ * Connect to an already registered MCP server and initialize the connection.
718
+ *
719
+ * For OAuth servers, returns `{ state: "authenticating", authUrl, clientId? }`.
720
+ * The user must complete the OAuth flow via the authUrl, which triggers a
721
+ * callback handled by `handleCallbackRequest()`.
722
+ *
723
+ * For non-OAuth servers, establishes the transport connection and returns
724
+ * `{ state: "connected" }`. Call `discoverIfConnected()` afterwards to
725
+ * discover capabilities and transition to "ready" state.
726
+ *
727
+ * @param id Server ID (must be registered first via registerServer())
728
+ * @returns Connection result with current state and OAuth info (if applicable)
729
+ */
730
+ async connectToServer(id) {
731
+ const conn = this.mcpConnections[id];
732
+ if (!conn) throw new Error(`Server ${id} is not registered. Call registerServer() first.`);
733
+ const error = await conn.init();
734
+ this._onServerStateChanged.fire();
735
+ switch (conn.connectionState) {
736
+ case MCPConnectionState.FAILED: return {
737
+ state: conn.connectionState,
738
+ error: error ?? "Unknown connection error"
739
+ };
740
+ case MCPConnectionState.AUTHENTICATING: {
741
+ const authUrl = conn.options.transport.authProvider?.authUrl;
742
+ const redirectUrl = conn.options.transport.authProvider?.redirectUrl;
743
+ if (!authUrl || !redirectUrl) return {
744
+ state: MCPConnectionState.FAILED,
745
+ error: `OAuth configuration incomplete: missing ${!authUrl ? "authUrl" : "redirectUrl"}`
746
+ };
747
+ const clientId = conn.options.transport.authProvider?.clientId;
748
+ const serverRow = this.getServersFromStorage().find((s) => s.id === id);
749
+ if (serverRow) this.saveServerToStorage({
750
+ ...serverRow,
751
+ auth_url: authUrl,
752
+ client_id: clientId ?? null
753
+ });
754
+ return {
755
+ state: conn.connectionState,
756
+ authUrl,
757
+ clientId
758
+ };
759
+ }
760
+ case MCPConnectionState.CONNECTED: return { state: conn.connectionState };
761
+ default: return {
762
+ state: MCPConnectionState.FAILED,
763
+ error: `Unexpected connection state after init: ${conn.connectionState}`
764
+ };
765
+ }
766
+ }
767
+ isCallbackRequest(req) {
768
+ if (req.method !== "GET") return false;
769
+ if (!req.url.includes("/callback")) return false;
770
+ return this.getServersFromStorage().some((server) => server.callback_url && req.url.startsWith(server.callback_url));
771
+ }
772
+ async handleCallbackRequest(req) {
773
+ const url = new URL(req.url);
774
+ const matchingServer = this.getServersFromStorage().find((server) => {
775
+ return server.callback_url && req.url.startsWith(server.callback_url);
776
+ });
777
+ if (!matchingServer) throw new Error(`No callback URI match found for the request url: ${req.url}. Was the request matched with \`isCallbackRequest()\`?`);
778
+ const serverId = matchingServer.id;
779
+ const code = url.searchParams.get("code");
780
+ const state = url.searchParams.get("state");
781
+ const error = url.searchParams.get("error");
782
+ const errorDescription = url.searchParams.get("error_description");
783
+ if (error) return {
784
+ serverId,
785
+ authSuccess: false,
786
+ authError: errorDescription || error
787
+ };
788
+ if (!code) throw new Error("Unauthorized: no code provided");
789
+ if (!state) throw new Error("Unauthorized: no state provided");
790
+ if (this.mcpConnections[serverId] === void 0) throw new Error(`Could not find serverId: ${serverId}`);
791
+ if (this.mcpConnections[serverId].connectionState === MCPConnectionState.READY || this.mcpConnections[serverId].connectionState === MCPConnectionState.CONNECTED) {
792
+ this.clearServerAuthUrl(serverId);
793
+ return {
794
+ serverId,
795
+ authSuccess: true
796
+ };
797
+ }
798
+ if (this.mcpConnections[serverId].connectionState !== MCPConnectionState.AUTHENTICATING) throw new Error(`Failed to authenticate: the client is in "${this.mcpConnections[serverId].connectionState}" state, expected "authenticating"`);
799
+ const conn = this.mcpConnections[serverId];
800
+ if (!conn.options.transport.authProvider) throw new Error("Trying to finalize authentication for a server connection without an authProvider");
801
+ const clientId = conn.options.transport.authProvider.clientId || state;
802
+ conn.options.transport.authProvider.clientId = clientId;
803
+ conn.options.transport.authProvider.serverId = serverId;
804
+ try {
805
+ await conn.completeAuthorization(code);
806
+ this.clearServerAuthUrl(serverId);
807
+ this._onServerStateChanged.fire();
808
+ return {
809
+ serverId,
810
+ authSuccess: true
811
+ };
812
+ } catch (error$1) {
813
+ const errorMessage = error$1 instanceof Error ? error$1.message : String(error$1);
814
+ this._onServerStateChanged.fire();
815
+ return {
816
+ serverId,
817
+ authSuccess: false,
818
+ authError: errorMessage
819
+ };
820
+ }
821
+ }
822
+ /**
823
+ * Discover server capabilities if connection is in CONNECTED or READY state.
824
+ * Transitions to DISCOVERING then READY (or CONNECTED on error).
825
+ * Can be called to refresh server capabilities (e.g., from a UI refresh button).
826
+ *
827
+ * If called while a previous discovery is in-flight for the same server,
828
+ * the previous discovery will be aborted.
829
+ *
830
+ * @param serverId The server ID to discover
831
+ * @param options Optional configuration
832
+ * @param options.timeoutMs Timeout in milliseconds (default: 30000)
833
+ * @returns Result with current state and optional error, or undefined if connection not found
834
+ */
835
+ async discoverIfConnected(serverId, options = {}) {
836
+ const conn = this.mcpConnections[serverId];
837
+ if (!conn) {
838
+ this._onObservabilityEvent.fire({
839
+ type: "mcp:client:discover",
840
+ displayMessage: `Connection not found for ${serverId}`,
841
+ payload: {},
842
+ timestamp: Date.now(),
843
+ id: nanoid()
844
+ });
845
+ return;
846
+ }
847
+ const result = await conn.discover(options);
848
+ this._onServerStateChanged.fire();
849
+ return {
850
+ ...result,
851
+ state: conn.connectionState
852
+ };
853
+ }
854
+ /**
855
+ * Establish connection in the background after OAuth completion
856
+ * This method connects to the server and discovers its capabilities
857
+ * @param serverId The server ID to establish connection for
858
+ */
859
+ async establishConnection(serverId) {
860
+ const conn = this.mcpConnections[serverId];
861
+ if (!conn) {
862
+ this._onObservabilityEvent.fire({
863
+ type: "mcp:client:preconnect",
864
+ displayMessage: `Connection not found for serverId: ${serverId}`,
865
+ payload: { serverId },
866
+ timestamp: Date.now(),
867
+ id: nanoid()
868
+ });
869
+ return;
870
+ }
871
+ if (conn.connectionState === MCPConnectionState.DISCOVERING || conn.connectionState === MCPConnectionState.READY) {
872
+ this._onObservabilityEvent.fire({
873
+ type: "mcp:client:connect",
874
+ displayMessage: `establishConnection skipped for ${serverId}, already in ${conn.connectionState} state`,
875
+ payload: {
876
+ url: conn.url.toString(),
877
+ transport: conn.options.transport.type || "unknown",
878
+ state: conn.connectionState
879
+ },
880
+ timestamp: Date.now(),
881
+ id: nanoid()
882
+ });
883
+ return;
884
+ }
885
+ const connectResult = await this.connectToServer(serverId);
886
+ this._onServerStateChanged.fire();
887
+ if (connectResult.state === MCPConnectionState.CONNECTED) await this.discoverIfConnected(serverId);
888
+ this._onObservabilityEvent.fire({
889
+ type: "mcp:client:connect",
890
+ displayMessage: `establishConnection completed for ${serverId}, final state: ${conn.connectionState}`,
891
+ payload: {
892
+ url: conn.url.toString(),
893
+ transport: conn.options.transport.type || "unknown",
894
+ state: conn.connectionState
895
+ },
896
+ timestamp: Date.now(),
897
+ id: nanoid()
898
+ });
899
+ }
900
+ /**
901
+ * Configure OAuth callback handling
902
+ * @param config OAuth callback configuration
903
+ */
904
+ configureOAuthCallback(config) {
905
+ this._oauthCallbackConfig = config;
906
+ }
907
+ /**
908
+ * Get the current OAuth callback configuration
909
+ * @returns The current OAuth callback configuration
910
+ */
911
+ getOAuthCallbackConfig() {
912
+ return this._oauthCallbackConfig;
913
+ }
914
+ /**
915
+ * @returns namespaced list of tools
916
+ */
917
+ listTools() {
918
+ return getNamespacedData(this.mcpConnections, "tools");
919
+ }
920
+ /**
921
+ * Lazy-loads the jsonSchema function from the AI SDK.
922
+ *
923
+ * This defers importing the "ai" package until it's actually needed, which helps reduce
924
+ * initial bundle size and startup time. The jsonSchema function is required for converting
925
+ * MCP tools into AI SDK tool definitions via getAITools().
926
+ *
927
+ * @internal This method is for internal use only. It's automatically called before operations
928
+ * that need jsonSchema (like getAITools() or OAuth flows). External consumers should not need
929
+ * to call this directly.
930
+ */
931
+ async ensureJsonSchema() {
932
+ if (!this.jsonSchema) {
933
+ const { jsonSchema } = await import("ai");
934
+ this.jsonSchema = jsonSchema;
935
+ }
936
+ }
937
+ /**
938
+ * @returns a set of tools that you can use with the AI SDK
939
+ */
940
+ getAITools() {
941
+ if (!this.jsonSchema) throw new Error("jsonSchema not initialized.");
942
+ for (const [id, conn] of Object.entries(this.mcpConnections)) if (conn.connectionState !== MCPConnectionState.READY && conn.connectionState !== MCPConnectionState.AUTHENTICATING) console.warn(`[getAITools] WARNING: Reading tools from connection ${id} in state "${conn.connectionState}". Tools may not be loaded yet.`);
943
+ return Object.fromEntries(getNamespacedData(this.mcpConnections, "tools").map((tool) => {
944
+ return [`tool_${tool.serverId.replace(/-/g, "")}_${tool.name}`, {
945
+ description: tool.description,
946
+ execute: async (args) => {
947
+ const result = await this.callTool({
948
+ arguments: args,
949
+ name: tool.name,
950
+ serverId: tool.serverId
951
+ });
952
+ if (result.isError) throw new Error(result.content[0].text);
953
+ return result;
954
+ },
955
+ inputSchema: this.jsonSchema(tool.inputSchema),
956
+ outputSchema: tool.outputSchema ? this.jsonSchema(tool.outputSchema) : void 0
957
+ }];
958
+ }));
959
+ }
960
+ /**
961
+ * @deprecated this has been renamed to getAITools(), and unstable_getAITools will be removed in the next major version
962
+ * @returns a set of tools that you can use with the AI SDK
963
+ */
964
+ unstable_getAITools() {
965
+ if (!this._didWarnAboutUnstableGetAITools) {
966
+ this._didWarnAboutUnstableGetAITools = true;
967
+ console.warn("unstable_getAITools is deprecated, use getAITools instead. unstable_getAITools will be removed in the next major version.");
968
+ }
969
+ return this.getAITools();
970
+ }
971
+ /**
972
+ * Closes all active in-memory connections to MCP servers.
973
+ *
974
+ * Note: This only closes the transport connections - it does NOT remove
975
+ * servers from storage. Servers will still be listed and their callback
976
+ * URLs will still match incoming OAuth requests.
977
+ *
978
+ * Use removeServer() instead if you want to fully clean up a server
979
+ * (closes connection AND removes from storage).
980
+ */
981
+ async closeAllConnections() {
982
+ const ids = Object.keys(this.mcpConnections);
983
+ for (const id of ids) this.mcpConnections[id].cancelDiscovery();
984
+ await Promise.all(ids.map(async (id) => {
985
+ await this.mcpConnections[id].client.close();
986
+ }));
987
+ for (const id of ids) {
988
+ const store = this._connectionDisposables.get(id);
989
+ if (store) store.dispose();
990
+ this._connectionDisposables.delete(id);
991
+ delete this.mcpConnections[id];
992
+ }
993
+ }
994
+ /**
995
+ * Closes a connection to an MCP server
996
+ * @param id The id of the connection to close
997
+ */
998
+ async closeConnection(id) {
999
+ if (!this.mcpConnections[id]) throw new Error(`Connection with id "${id}" does not exist.`);
1000
+ this.mcpConnections[id].cancelDiscovery();
1001
+ await this.mcpConnections[id].client.close();
1002
+ delete this.mcpConnections[id];
1003
+ const store = this._connectionDisposables.get(id);
1004
+ if (store) store.dispose();
1005
+ this._connectionDisposables.delete(id);
1006
+ }
1007
+ /**
1008
+ * Remove an MCP server - closes connection if active and removes from storage.
1009
+ */
1010
+ async removeServer(serverId) {
1011
+ if (this.mcpConnections[serverId]) try {
1012
+ await this.closeConnection(serverId);
1013
+ } catch (e) {}
1014
+ this.removeServerFromStorage(serverId);
1015
+ this._onServerStateChanged.fire();
1016
+ }
1017
+ /**
1018
+ * List all MCP servers from storage
1019
+ */
1020
+ listServers() {
1021
+ return this.getServersFromStorage();
1022
+ }
1023
+ /**
1024
+ * Dispose the manager and all resources.
1025
+ */
1026
+ async dispose() {
1027
+ try {
1028
+ await this.closeAllConnections();
1029
+ } finally {
1030
+ this._onServerStateChanged.dispose();
1031
+ this._onObservabilityEvent.dispose();
1032
+ }
1033
+ }
1034
+ /**
1035
+ * @returns namespaced list of prompts
1036
+ */
1037
+ listPrompts() {
1038
+ return getNamespacedData(this.mcpConnections, "prompts");
1039
+ }
1040
+ /**
1041
+ * @returns namespaced list of tools
1042
+ */
1043
+ listResources() {
1044
+ return getNamespacedData(this.mcpConnections, "resources");
1045
+ }
1046
+ /**
1047
+ * @returns namespaced list of resource templates
1048
+ */
1049
+ listResourceTemplates() {
1050
+ return getNamespacedData(this.mcpConnections, "resourceTemplates");
1051
+ }
1052
+ /**
1053
+ * Namespaced version of callTool
1054
+ */
1055
+ async callTool(params, resultSchema, options) {
1056
+ const unqualifiedName = params.name.replace(`${params.serverId}.`, "");
1057
+ return this.mcpConnections[params.serverId].client.callTool({
1058
+ ...params,
1059
+ name: unqualifiedName
1060
+ }, resultSchema, options);
1061
+ }
1062
+ /**
1063
+ * Namespaced version of readResource
1064
+ */
1065
+ readResource(params, options) {
1066
+ return this.mcpConnections[params.serverId].client.readResource(params, options);
1067
+ }
1068
+ /**
1069
+ * Namespaced version of getPrompt
1070
+ */
1071
+ getPrompt(params, options) {
1072
+ return this.mcpConnections[params.serverId].client.getPrompt(params, options);
1073
+ }
1074
+ };
1075
+ function getNamespacedData(mcpClients, type) {
1076
+ return Object.entries(mcpClients).map(([name, conn]) => {
1077
+ return {
1078
+ data: conn[type],
1079
+ name
1080
+ };
1081
+ }).flatMap(({ name: serverId, data }) => {
1082
+ return data.map((item) => {
1083
+ return {
1084
+ ...item,
1085
+ serverId
1086
+ };
1087
+ });
1088
+ });
1089
+ }
1090
+
1091
+ //#endregion
1092
+ export { DisposableStore as i, getNamespacedData as n, MCPConnectionState as r, MCPClientManager as t };
1093
+ //# sourceMappingURL=client-BZq9qau2.js.map