agents 0.2.1 → 0.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ai-chat-agent.d.ts +2 -1
- package/dist/ai-chat-agent.js +348 -56
- package/dist/ai-chat-agent.js.map +1 -1
- package/dist/ai-react.d.ts +2 -1
- package/dist/{chunk-RS5OCNEQ.js → chunk-254F4GDT.js} +67 -47
- package/dist/chunk-254F4GDT.js.map +1 -0
- package/dist/{chunk-QEPGNUG6.js → chunk-3OT2NNEW.js} +364 -73
- package/dist/chunk-3OT2NNEW.js.map +1 -0
- package/dist/{chunk-XFS5ERG3.js → chunk-Z44WASMA.js} +1 -14
- package/dist/chunk-Z44WASMA.js.map +1 -0
- package/dist/{client-BohGLma8.d.ts → client-DVoPb3-C.d.ts} +110 -31
- package/dist/codemode/ai.d.ts +25 -0
- package/dist/codemode/ai.js +5112 -0
- package/dist/codemode/ai.js.map +1 -0
- package/dist/index.d.ts +17 -31
- package/dist/index.js +3 -3
- package/dist/mcp/client.d.ts +2 -1
- package/dist/mcp/client.js +1 -1
- package/dist/mcp/do-oauth-client-provider.d.ts +0 -8
- package/dist/mcp/do-oauth-client-provider.js +1 -1
- package/dist/mcp/index.d.ts +3 -2
- package/dist/mcp/index.js +3 -3
- package/dist/mcp/index.js.map +1 -1
- package/dist/mcp/x402.d.ts +3 -1
- package/dist/mcp/x402.js +3 -3
- package/dist/mcp/x402.js.map +1 -1
- package/dist/mcp-BH1fJeiU.d.ts +58 -0
- package/dist/observability/index.d.ts +12 -24
- package/dist/observability/index.js +3 -3
- package/dist/react.d.ts +10 -6
- package/dist/react.js +99 -2
- package/dist/react.js.map +1 -1
- package/package.json +13 -6
- package/src/index.ts +97 -53
- package/dist/chunk-QEPGNUG6.js.map +0 -1
- package/dist/chunk-RS5OCNEQ.js.map +0 -1
- package/dist/chunk-XFS5ERG3.js.map +0 -1
|
@@ -1,15 +1,72 @@
|
|
|
1
1
|
// src/mcp/client.ts
|
|
2
2
|
import { jsonSchema } from "ai";
|
|
3
|
-
import { nanoid } from "nanoid";
|
|
3
|
+
import { nanoid as nanoid2 } from "nanoid";
|
|
4
|
+
|
|
5
|
+
// src/core/events.ts
|
|
6
|
+
function toDisposable(fn) {
|
|
7
|
+
return { dispose: fn };
|
|
8
|
+
}
|
|
9
|
+
var DisposableStore = class {
|
|
10
|
+
constructor() {
|
|
11
|
+
this._items = [];
|
|
12
|
+
}
|
|
13
|
+
add(d) {
|
|
14
|
+
this._items.push(d);
|
|
15
|
+
return d;
|
|
16
|
+
}
|
|
17
|
+
dispose() {
|
|
18
|
+
while (this._items.length) {
|
|
19
|
+
try {
|
|
20
|
+
this._items.pop().dispose();
|
|
21
|
+
} catch {
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
var Emitter = class {
|
|
27
|
+
constructor() {
|
|
28
|
+
this._listeners = /* @__PURE__ */ new Set();
|
|
29
|
+
this.event = (listener) => {
|
|
30
|
+
this._listeners.add(listener);
|
|
31
|
+
return toDisposable(() => this._listeners.delete(listener));
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
fire(data) {
|
|
35
|
+
for (const listener of [...this._listeners]) {
|
|
36
|
+
try {
|
|
37
|
+
listener(data);
|
|
38
|
+
} catch (err) {
|
|
39
|
+
console.error("Emitter listener error:", err);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
dispose() {
|
|
44
|
+
this._listeners.clear();
|
|
45
|
+
}
|
|
46
|
+
};
|
|
4
47
|
|
|
5
48
|
// src/mcp/client-connection.ts
|
|
6
49
|
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
7
50
|
import {
|
|
51
|
+
ElicitRequestSchema,
|
|
8
52
|
PromptListChangedNotificationSchema,
|
|
9
53
|
ResourceListChangedNotificationSchema,
|
|
10
|
-
ToolListChangedNotificationSchema
|
|
11
|
-
ElicitRequestSchema
|
|
54
|
+
ToolListChangedNotificationSchema
|
|
12
55
|
} from "@modelcontextprotocol/sdk/types.js";
|
|
56
|
+
import { nanoid } from "nanoid";
|
|
57
|
+
|
|
58
|
+
// src/mcp/errors.ts
|
|
59
|
+
function toErrorMessage(error) {
|
|
60
|
+
return error instanceof Error ? error.message : String(error);
|
|
61
|
+
}
|
|
62
|
+
function isUnauthorized(error) {
|
|
63
|
+
const msg = toErrorMessage(error);
|
|
64
|
+
return msg.includes("Unauthorized") || msg.includes("401");
|
|
65
|
+
}
|
|
66
|
+
function isTransportNotImplemented(error) {
|
|
67
|
+
const msg = toErrorMessage(error);
|
|
68
|
+
return msg.includes("404") || msg.includes("405") || msg.includes("Not Implemented") || msg.includes("not implemented");
|
|
69
|
+
}
|
|
13
70
|
|
|
14
71
|
// src/mcp/sse-edge.ts
|
|
15
72
|
import {
|
|
@@ -118,7 +175,8 @@ var MCPClientConnection = class {
|
|
|
118
175
|
this.prompts = [];
|
|
119
176
|
this.resources = [];
|
|
120
177
|
this.resourceTemplates = [];
|
|
121
|
-
this.
|
|
178
|
+
this._onObservabilityEvent = new Emitter();
|
|
179
|
+
this.onObservabilityEvent = this._onObservabilityEvent.event;
|
|
122
180
|
const clientOptions = {
|
|
123
181
|
...options.client,
|
|
124
182
|
capabilities: {
|
|
@@ -131,23 +189,112 @@ var MCPClientConnection = class {
|
|
|
131
189
|
/**
|
|
132
190
|
* Initialize a client connection
|
|
133
191
|
*
|
|
134
|
-
* @param code Optional OAuth code to initialize the connection with if auth hasn't been initialized
|
|
135
192
|
* @returns
|
|
136
193
|
*/
|
|
137
|
-
async init(
|
|
194
|
+
async init() {
|
|
195
|
+
const transportType = this.options.transport.type;
|
|
196
|
+
if (!transportType) {
|
|
197
|
+
throw new Error("Transport type must be specified");
|
|
198
|
+
}
|
|
138
199
|
try {
|
|
139
|
-
|
|
140
|
-
await this.tryConnect(transportType, code);
|
|
200
|
+
await this.tryConnect(transportType);
|
|
141
201
|
} catch (e) {
|
|
142
|
-
if (e
|
|
202
|
+
if (isUnauthorized(e)) {
|
|
143
203
|
this.connectionState = "authenticating";
|
|
144
204
|
return;
|
|
145
205
|
}
|
|
206
|
+
this._onObservabilityEvent.fire({
|
|
207
|
+
type: "mcp:client:connect",
|
|
208
|
+
displayMessage: `Connection initialization failed for ${this.url.toString()}`,
|
|
209
|
+
payload: {
|
|
210
|
+
url: this.url.toString(),
|
|
211
|
+
transport: transportType,
|
|
212
|
+
state: this.connectionState,
|
|
213
|
+
error: toErrorMessage(e)
|
|
214
|
+
},
|
|
215
|
+
timestamp: Date.now(),
|
|
216
|
+
id: nanoid()
|
|
217
|
+
});
|
|
146
218
|
this.connectionState = "failed";
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
await this.discoverAndRegister();
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Finish OAuth by probing transports based on configured type.
|
|
225
|
+
* - Explicit: finish on that transport
|
|
226
|
+
* - Auto: try streamable-http, then sse on 404/405/Not Implemented
|
|
227
|
+
*/
|
|
228
|
+
async finishAuthProbe(code) {
|
|
229
|
+
if (!this.options.transport.authProvider) {
|
|
230
|
+
throw new Error("No auth provider configured");
|
|
231
|
+
}
|
|
232
|
+
const configuredType = this.options.transport.type;
|
|
233
|
+
if (!configuredType) {
|
|
234
|
+
throw new Error("Transport type must be specified");
|
|
235
|
+
}
|
|
236
|
+
const finishAuth = async (base) => {
|
|
237
|
+
const transport = this.getTransport(base);
|
|
238
|
+
await transport.finishAuth(code);
|
|
239
|
+
};
|
|
240
|
+
if (configuredType === "sse" || configuredType === "streamable-http") {
|
|
241
|
+
await finishAuth(configuredType);
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
try {
|
|
245
|
+
await finishAuth("streamable-http");
|
|
246
|
+
} catch (e) {
|
|
247
|
+
if (isTransportNotImplemented(e)) {
|
|
248
|
+
await finishAuth("sse");
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
147
251
|
throw e;
|
|
148
252
|
}
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* Complete OAuth authorization
|
|
256
|
+
*/
|
|
257
|
+
async completeAuthorization(code) {
|
|
258
|
+
if (this.connectionState !== "authenticating") {
|
|
259
|
+
throw new Error(
|
|
260
|
+
"Connection must be in authenticating state to complete authorization"
|
|
261
|
+
);
|
|
262
|
+
}
|
|
263
|
+
try {
|
|
264
|
+
await this.finishAuthProbe(code);
|
|
265
|
+
this.connectionState = "connecting";
|
|
266
|
+
} catch (error) {
|
|
267
|
+
this.connectionState = "failed";
|
|
268
|
+
throw error;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* Establish connection after successful authorization
|
|
273
|
+
*/
|
|
274
|
+
async establishConnection() {
|
|
275
|
+
if (this.connectionState !== "connecting") {
|
|
276
|
+
throw new Error(
|
|
277
|
+
"Connection must be in connecting state to establish connection"
|
|
278
|
+
);
|
|
279
|
+
}
|
|
280
|
+
try {
|
|
281
|
+
const transportType = this.options.transport.type;
|
|
282
|
+
if (!transportType) {
|
|
283
|
+
throw new Error("Transport type must be specified");
|
|
284
|
+
}
|
|
285
|
+
await this.tryConnect(transportType);
|
|
286
|
+
await this.discoverAndRegister();
|
|
287
|
+
} catch (error) {
|
|
288
|
+
this.connectionState = "failed";
|
|
289
|
+
throw error;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* Discover server capabilities and register tools, resources, prompts, and templates
|
|
294
|
+
*/
|
|
295
|
+
async discoverAndRegister() {
|
|
149
296
|
this.connectionState = "discovering";
|
|
150
|
-
this.serverCapabilities =
|
|
297
|
+
this.serverCapabilities = this.client.getServerCapabilities();
|
|
151
298
|
if (!this.serverCapabilities) {
|
|
152
299
|
throw new Error("The MCP Server failed to return server capabilities");
|
|
153
300
|
}
|
|
@@ -173,7 +320,18 @@ var MCPClientConnection = class {
|
|
|
173
320
|
];
|
|
174
321
|
for (const { name, result } of operations) {
|
|
175
322
|
if (result.status === "rejected") {
|
|
176
|
-
|
|
323
|
+
const url = this.url.toString();
|
|
324
|
+
this._onObservabilityEvent.fire({
|
|
325
|
+
type: "mcp:client:discover",
|
|
326
|
+
displayMessage: `Failed to discover ${name} for ${url}`,
|
|
327
|
+
payload: {
|
|
328
|
+
url,
|
|
329
|
+
capability: name,
|
|
330
|
+
error: result.reason
|
|
331
|
+
},
|
|
332
|
+
timestamp: Date.now(),
|
|
333
|
+
id: nanoid()
|
|
334
|
+
});
|
|
177
335
|
}
|
|
178
336
|
}
|
|
179
337
|
this.instructions = instructionsResult.status === "fulfilled" ? instructionsResult.value : void 0;
|
|
@@ -240,7 +398,7 @@ var MCPClientConnection = class {
|
|
|
240
398
|
do {
|
|
241
399
|
toolsResult = await this.client.listTools({
|
|
242
400
|
cursor: toolsResult.nextCursor
|
|
243
|
-
}).catch(
|
|
401
|
+
}).catch(this._capabilityErrorHandler({ tools: [] }, "tools/list"));
|
|
244
402
|
toolsAgg = toolsAgg.concat(toolsResult.tools);
|
|
245
403
|
} while (toolsResult.nextCursor);
|
|
246
404
|
return toolsAgg;
|
|
@@ -251,7 +409,9 @@ var MCPClientConnection = class {
|
|
|
251
409
|
do {
|
|
252
410
|
resourcesResult = await this.client.listResources({
|
|
253
411
|
cursor: resourcesResult.nextCursor
|
|
254
|
-
}).catch(
|
|
412
|
+
}).catch(
|
|
413
|
+
this._capabilityErrorHandler({ resources: [] }, "resources/list")
|
|
414
|
+
);
|
|
255
415
|
resourcesAgg = resourcesAgg.concat(resourcesResult.resources);
|
|
256
416
|
} while (resourcesResult.nextCursor);
|
|
257
417
|
return resourcesAgg;
|
|
@@ -262,7 +422,7 @@ var MCPClientConnection = class {
|
|
|
262
422
|
do {
|
|
263
423
|
promptsResult = await this.client.listPrompts({
|
|
264
424
|
cursor: promptsResult.nextCursor
|
|
265
|
-
}).catch(
|
|
425
|
+
}).catch(this._capabilityErrorHandler({ prompts: [] }, "prompts/list"));
|
|
266
426
|
promptsAgg = promptsAgg.concat(promptsResult.prompts);
|
|
267
427
|
} while (promptsResult.nextCursor);
|
|
268
428
|
return promptsAgg;
|
|
@@ -276,7 +436,7 @@ var MCPClientConnection = class {
|
|
|
276
436
|
templatesResult = await this.client.listResourceTemplates({
|
|
277
437
|
cursor: templatesResult.nextCursor
|
|
278
438
|
}).catch(
|
|
279
|
-
|
|
439
|
+
this._capabilityErrorHandler(
|
|
280
440
|
{ resourceTemplates: [] },
|
|
281
441
|
"resources/templates/list"
|
|
282
442
|
)
|
|
@@ -315,37 +475,46 @@ var MCPClientConnection = class {
|
|
|
315
475
|
throw new Error(`Unsupported transport type: ${transportType}`);
|
|
316
476
|
}
|
|
317
477
|
}
|
|
318
|
-
async tryConnect(transportType
|
|
319
|
-
|
|
320
|
-
if (code && this.options.transport.authProvider) {
|
|
321
|
-
const savedTransport = await this.options.transport.authProvider.getOAuthTransport();
|
|
322
|
-
if (savedTransport) {
|
|
323
|
-
effectiveTransportType = savedTransport;
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
const transports = effectiveTransportType === "auto" ? ["streamable-http", "sse"] : [effectiveTransportType];
|
|
478
|
+
async tryConnect(transportType) {
|
|
479
|
+
const transports = transportType === "auto" ? ["streamable-http", "sse"] : [transportType];
|
|
327
480
|
for (const currentTransportType of transports) {
|
|
328
481
|
const isLastTransport = currentTransportType === transports[transports.length - 1];
|
|
329
|
-
const hasFallback =
|
|
482
|
+
const hasFallback = transportType === "auto" && currentTransportType === "streamable-http" && !isLastTransport;
|
|
330
483
|
const transport = this.getTransport(currentTransportType);
|
|
331
|
-
if (code) {
|
|
332
|
-
await transport.finishAuth(code);
|
|
333
|
-
}
|
|
334
484
|
try {
|
|
335
485
|
await this.client.connect(transport);
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
486
|
+
this.lastConnectedTransport = currentTransportType;
|
|
487
|
+
const url = this.url.toString();
|
|
488
|
+
this._onObservabilityEvent.fire({
|
|
489
|
+
type: "mcp:client:connect",
|
|
490
|
+
displayMessage: `Connected successfully using ${currentTransportType} transport for ${url}`,
|
|
491
|
+
payload: {
|
|
492
|
+
url,
|
|
493
|
+
transport: currentTransportType,
|
|
494
|
+
state: this.connectionState
|
|
495
|
+
},
|
|
496
|
+
timestamp: Date.now(),
|
|
497
|
+
id: nanoid()
|
|
498
|
+
});
|
|
339
499
|
break;
|
|
340
500
|
} catch (e) {
|
|
341
501
|
const error = e instanceof Error ? e : new Error(String(e));
|
|
342
|
-
if (
|
|
343
|
-
await this.options.transport.authProvider.saveOAuthTransport(
|
|
344
|
-
currentTransportType
|
|
345
|
-
);
|
|
502
|
+
if (isUnauthorized(error)) {
|
|
346
503
|
throw e;
|
|
347
504
|
}
|
|
348
|
-
if (hasFallback && (error
|
|
505
|
+
if (hasFallback && isTransportNotImplemented(error)) {
|
|
506
|
+
const url = this.url.toString();
|
|
507
|
+
this._onObservabilityEvent.fire({
|
|
508
|
+
type: "mcp:client:connect",
|
|
509
|
+
displayMessage: `${currentTransportType} transport not available, trying ${transports[transports.indexOf(currentTransportType) + 1]} for ${url}`,
|
|
510
|
+
payload: {
|
|
511
|
+
url,
|
|
512
|
+
transport: currentTransportType,
|
|
513
|
+
state: this.connectionState
|
|
514
|
+
},
|
|
515
|
+
timestamp: Date.now(),
|
|
516
|
+
id: nanoid()
|
|
517
|
+
});
|
|
349
518
|
continue;
|
|
350
519
|
}
|
|
351
520
|
throw e;
|
|
@@ -358,18 +527,27 @@ var MCPClientConnection = class {
|
|
|
358
527
|
}
|
|
359
528
|
);
|
|
360
529
|
}
|
|
530
|
+
_capabilityErrorHandler(empty, method) {
|
|
531
|
+
return (e) => {
|
|
532
|
+
if (e.code === -32601) {
|
|
533
|
+
const url = this.url.toString();
|
|
534
|
+
this._onObservabilityEvent.fire({
|
|
535
|
+
type: "mcp:client:discover",
|
|
536
|
+
displayMessage: `The server advertised support for the capability ${method.split("/")[0]}, but returned "Method not found" for '${method}' for ${url}`,
|
|
537
|
+
payload: {
|
|
538
|
+
url,
|
|
539
|
+
capability: method.split("/")[0],
|
|
540
|
+
error: toErrorMessage(e)
|
|
541
|
+
},
|
|
542
|
+
timestamp: Date.now(),
|
|
543
|
+
id: nanoid()
|
|
544
|
+
});
|
|
545
|
+
return empty;
|
|
546
|
+
}
|
|
547
|
+
throw e;
|
|
548
|
+
};
|
|
549
|
+
}
|
|
361
550
|
};
|
|
362
|
-
function capabilityErrorHandler(empty, method) {
|
|
363
|
-
return (e) => {
|
|
364
|
-
if (e.code === -32601) {
|
|
365
|
-
console.error(
|
|
366
|
-
`The server advertised support for the capability ${method.split("/")[0]}, but returned "Method not found" for '${method}'.`
|
|
367
|
-
);
|
|
368
|
-
return empty;
|
|
369
|
-
}
|
|
370
|
-
throw e;
|
|
371
|
-
};
|
|
372
|
-
}
|
|
373
551
|
|
|
374
552
|
// src/mcp/client.ts
|
|
375
553
|
var MCPClientManager = class {
|
|
@@ -384,6 +562,11 @@ var MCPClientManager = class {
|
|
|
384
562
|
this.mcpConnections = {};
|
|
385
563
|
this._callbackUrls = [];
|
|
386
564
|
this._didWarnAboutUnstableGetAITools = false;
|
|
565
|
+
this._connectionDisposables = /* @__PURE__ */ new Map();
|
|
566
|
+
this._onObservabilityEvent = new Emitter();
|
|
567
|
+
this.onObservabilityEvent = this._onObservabilityEvent.event;
|
|
568
|
+
this._onConnected = new Emitter();
|
|
569
|
+
this.onConnected = this._onConnected.event;
|
|
387
570
|
}
|
|
388
571
|
/**
|
|
389
572
|
* Connect to and register an MCP server
|
|
@@ -393,18 +576,18 @@ var MCPClientManager = class {
|
|
|
393
576
|
* @param capabilities Client capabilities (i.e. if the client supports roots/sampling)
|
|
394
577
|
*/
|
|
395
578
|
async connect(url, options = {}) {
|
|
396
|
-
const id = options.reconnect?.id ??
|
|
397
|
-
if (
|
|
398
|
-
console.warn(
|
|
399
|
-
"No authProvider provided in the transport options. This client will only support unauthenticated remote MCP Servers"
|
|
400
|
-
);
|
|
401
|
-
} else {
|
|
579
|
+
const id = options.reconnect?.id ?? nanoid2(8);
|
|
580
|
+
if (options.transport?.authProvider) {
|
|
402
581
|
options.transport.authProvider.serverId = id;
|
|
403
582
|
if (options.reconnect?.oauthClientId) {
|
|
404
583
|
options.transport.authProvider.clientId = options.reconnect?.oauthClientId;
|
|
405
584
|
}
|
|
406
585
|
}
|
|
407
586
|
if (!options.reconnect?.oauthCode || !this.mcpConnections[id]) {
|
|
587
|
+
const normalizedTransport = {
|
|
588
|
+
...options.transport,
|
|
589
|
+
type: options.transport?.type ?? "auto"
|
|
590
|
+
};
|
|
408
591
|
this.mcpConnections[id] = new MCPClientConnection(
|
|
409
592
|
new URL(url),
|
|
410
593
|
{
|
|
@@ -413,13 +596,44 @@ var MCPClientManager = class {
|
|
|
413
596
|
},
|
|
414
597
|
{
|
|
415
598
|
client: options.client ?? {},
|
|
416
|
-
transport:
|
|
599
|
+
transport: normalizedTransport
|
|
417
600
|
}
|
|
418
601
|
);
|
|
602
|
+
const store = new DisposableStore();
|
|
603
|
+
const existing = this._connectionDisposables.get(id);
|
|
604
|
+
if (existing) existing.dispose();
|
|
605
|
+
this._connectionDisposables.set(id, store);
|
|
606
|
+
store.add(
|
|
607
|
+
this.mcpConnections[id].onObservabilityEvent((event) => {
|
|
608
|
+
this._onObservabilityEvent.fire(event);
|
|
609
|
+
})
|
|
610
|
+
);
|
|
611
|
+
}
|
|
612
|
+
await this.mcpConnections[id].init();
|
|
613
|
+
if (options.reconnect?.oauthCode) {
|
|
614
|
+
try {
|
|
615
|
+
await this.mcpConnections[id].completeAuthorization(
|
|
616
|
+
options.reconnect.oauthCode
|
|
617
|
+
);
|
|
618
|
+
await this.mcpConnections[id].establishConnection();
|
|
619
|
+
} catch (error) {
|
|
620
|
+
this._onObservabilityEvent.fire({
|
|
621
|
+
type: "mcp:client:connect",
|
|
622
|
+
displayMessage: `Failed to complete OAuth reconnection for ${id} for ${url}`,
|
|
623
|
+
payload: {
|
|
624
|
+
url,
|
|
625
|
+
transport: options.transport?.type ?? "auto",
|
|
626
|
+
state: this.mcpConnections[id].connectionState,
|
|
627
|
+
error: toErrorMessage(error)
|
|
628
|
+
},
|
|
629
|
+
timestamp: Date.now(),
|
|
630
|
+
id
|
|
631
|
+
});
|
|
632
|
+
throw error;
|
|
633
|
+
}
|
|
419
634
|
}
|
|
420
|
-
await this.mcpConnections[id].init(options.reconnect?.oauthCode);
|
|
421
635
|
const authUrl = options.transport?.authProvider?.authUrl;
|
|
422
|
-
if (authUrl && options.transport?.authProvider?.redirectUrl) {
|
|
636
|
+
if (this.mcpConnections[id].connectionState === "authenticating" && authUrl && options.transport?.authProvider?.redirectUrl) {
|
|
423
637
|
this._callbackUrls.push(
|
|
424
638
|
options.transport.authProvider.redirectUrl.toString()
|
|
425
639
|
);
|
|
@@ -474,19 +688,56 @@ var MCPClientManager = class {
|
|
|
474
688
|
}
|
|
475
689
|
conn.options.transport.authProvider.clientId = clientId;
|
|
476
690
|
conn.options.transport.authProvider.serverId = serverId;
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
691
|
+
try {
|
|
692
|
+
await conn.completeAuthorization(code);
|
|
693
|
+
return {
|
|
694
|
+
serverId,
|
|
695
|
+
authSuccess: true
|
|
696
|
+
};
|
|
697
|
+
} catch (error) {
|
|
698
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
699
|
+
return {
|
|
700
|
+
serverId,
|
|
701
|
+
authSuccess: false,
|
|
702
|
+
authError: errorMessage
|
|
703
|
+
};
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
/**
|
|
707
|
+
* Establish connection in the background after OAuth completion
|
|
708
|
+
* This method is called asynchronously and doesn't block the OAuth callback response
|
|
709
|
+
* @param serverId The server ID to establish connection for
|
|
710
|
+
*/
|
|
711
|
+
async establishConnection(serverId) {
|
|
712
|
+
const conn = this.mcpConnections[serverId];
|
|
713
|
+
if (!conn) {
|
|
714
|
+
this._onObservabilityEvent.fire({
|
|
715
|
+
type: "mcp:client:preconnect",
|
|
716
|
+
displayMessage: `Connection not found for serverId: ${serverId}`,
|
|
717
|
+
payload: { serverId },
|
|
718
|
+
timestamp: Date.now(),
|
|
719
|
+
id: nanoid2()
|
|
720
|
+
});
|
|
721
|
+
return;
|
|
722
|
+
}
|
|
723
|
+
try {
|
|
724
|
+
await conn.establishConnection();
|
|
725
|
+
this._onConnected.fire(serverId);
|
|
726
|
+
} catch (error) {
|
|
727
|
+
const url = conn.url.toString();
|
|
728
|
+
this._onObservabilityEvent.fire({
|
|
729
|
+
type: "mcp:client:connect",
|
|
730
|
+
displayMessage: `Failed to establish connection to server ${serverId} with url ${url}`,
|
|
731
|
+
payload: {
|
|
732
|
+
url,
|
|
733
|
+
transport: conn.options.transport.type ?? "auto",
|
|
734
|
+
state: conn.connectionState,
|
|
735
|
+
error: toErrorMessage(error)
|
|
736
|
+
},
|
|
737
|
+
timestamp: Date.now(),
|
|
738
|
+
id: nanoid2()
|
|
739
|
+
});
|
|
488
740
|
}
|
|
489
|
-
return { serverId };
|
|
490
741
|
}
|
|
491
742
|
/**
|
|
492
743
|
* Register a callback URL for OAuth handling
|
|
@@ -506,6 +757,20 @@ var MCPClientManager = class {
|
|
|
506
757
|
(url) => !url.endsWith(`/${serverId}`)
|
|
507
758
|
);
|
|
508
759
|
}
|
|
760
|
+
/**
|
|
761
|
+
* Configure OAuth callback handling
|
|
762
|
+
* @param config OAuth callback configuration
|
|
763
|
+
*/
|
|
764
|
+
configureOAuthCallback(config) {
|
|
765
|
+
this._oauthCallbackConfig = config;
|
|
766
|
+
}
|
|
767
|
+
/**
|
|
768
|
+
* Get the current OAuth callback configuration
|
|
769
|
+
* @returns The current OAuth callback configuration
|
|
770
|
+
*/
|
|
771
|
+
getOAuthCallbackConfig() {
|
|
772
|
+
return this._oauthCallbackConfig;
|
|
773
|
+
}
|
|
509
774
|
/**
|
|
510
775
|
* @returns namespaced list of tools
|
|
511
776
|
*/
|
|
@@ -533,8 +798,12 @@ var MCPClientManager = class {
|
|
|
533
798
|
}
|
|
534
799
|
return result;
|
|
535
800
|
},
|
|
801
|
+
// @ts-expect-error drift between ai and mcp types
|
|
536
802
|
inputSchema: jsonSchema(tool.inputSchema),
|
|
537
|
-
outputSchema: tool.outputSchema ?
|
|
803
|
+
outputSchema: tool.outputSchema ? (
|
|
804
|
+
// @ts-expect-error drift between ai and mcp types
|
|
805
|
+
jsonSchema(tool.outputSchema)
|
|
806
|
+
) : void 0
|
|
538
807
|
}
|
|
539
808
|
];
|
|
540
809
|
})
|
|
@@ -557,11 +826,18 @@ var MCPClientManager = class {
|
|
|
557
826
|
* Closes all connections to MCP servers
|
|
558
827
|
*/
|
|
559
828
|
async closeAllConnections() {
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
829
|
+
const ids = Object.keys(this.mcpConnections);
|
|
830
|
+
await Promise.all(
|
|
831
|
+
ids.map(async (id) => {
|
|
832
|
+
await this.mcpConnections[id].client.close();
|
|
563
833
|
})
|
|
564
834
|
);
|
|
835
|
+
for (const id of ids) {
|
|
836
|
+
const store = this._connectionDisposables.get(id);
|
|
837
|
+
if (store) store.dispose();
|
|
838
|
+
this._connectionDisposables.delete(id);
|
|
839
|
+
delete this.mcpConnections[id];
|
|
840
|
+
}
|
|
565
841
|
}
|
|
566
842
|
/**
|
|
567
843
|
* Closes a connection to an MCP server
|
|
@@ -573,6 +849,20 @@ var MCPClientManager = class {
|
|
|
573
849
|
}
|
|
574
850
|
await this.mcpConnections[id].client.close();
|
|
575
851
|
delete this.mcpConnections[id];
|
|
852
|
+
const store = this._connectionDisposables.get(id);
|
|
853
|
+
if (store) store.dispose();
|
|
854
|
+
this._connectionDisposables.delete(id);
|
|
855
|
+
}
|
|
856
|
+
/**
|
|
857
|
+
* Dispose the manager and all resources.
|
|
858
|
+
*/
|
|
859
|
+
async dispose() {
|
|
860
|
+
try {
|
|
861
|
+
await this.closeAllConnections();
|
|
862
|
+
} finally {
|
|
863
|
+
this._onConnected.dispose();
|
|
864
|
+
this._onObservabilityEvent.dispose();
|
|
865
|
+
}
|
|
576
866
|
}
|
|
577
867
|
/**
|
|
578
868
|
* @returns namespaced list of prompts
|
|
@@ -642,9 +932,10 @@ function getNamespacedData(mcpClients, type) {
|
|
|
642
932
|
}
|
|
643
933
|
|
|
644
934
|
export {
|
|
935
|
+
DisposableStore,
|
|
645
936
|
SSEEdgeClientTransport,
|
|
646
937
|
StreamableHTTPEdgeClientTransport,
|
|
647
938
|
MCPClientManager,
|
|
648
939
|
getNamespacedData
|
|
649
940
|
};
|
|
650
|
-
//# sourceMappingURL=chunk-
|
|
941
|
+
//# sourceMappingURL=chunk-3OT2NNEW.js.map
|