agents 0.2.23 → 0.2.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -3
- package/dist/ai-chat-agent.d.ts +86 -13
- package/dist/ai-chat-agent.js +340 -74
- package/dist/ai-chat-agent.js.map +1 -1
- package/dist/{ai-chat-v5-migration-DBHGW4Hv.js → ai-chat-v5-migration-BSiGZmYU.js} +1 -1
- package/dist/{ai-chat-v5-migration-DBHGW4Hv.js.map → ai-chat-v5-migration-BSiGZmYU.js.map} +1 -1
- package/dist/ai-chat-v5-migration.js +1 -1
- package/dist/ai-react.d.ts +14 -9
- package/dist/ai-react.js +164 -29
- package/dist/ai-react.js.map +1 -1
- package/dist/{ai-types-D5YoPrBZ.d.ts → ai-types-81H_-Uxh.d.ts} +15 -7
- package/dist/{ai-types-B3aQaFv3.js → ai-types-CrMqkwc_.js} +5 -1
- package/dist/ai-types-CrMqkwc_.js.map +1 -0
- package/dist/ai-types.d.ts +1 -1
- package/dist/ai-types.js +1 -1
- package/dist/{client-BfiZ3HQd.js → client-B3SR12TQ.js} +2 -2
- package/dist/{client-BfiZ3HQd.js.map → client-B3SR12TQ.js.map} +1 -1
- package/dist/{client-CbWe9FBd.d.ts → client-BAQA84dr.d.ts} +2 -2
- package/dist/client-BZq9qau2.js +1093 -0
- package/dist/client-BZq9qau2.js.map +1 -0
- package/dist/client-CsaP9Irq.d.ts +1528 -0
- package/dist/client.d.ts +2 -2
- package/dist/client.js +2 -2
- package/dist/codemode/ai.js +5 -5
- package/dist/{do-oauth-client-provider-DGc5pP0l.d.ts → do-oauth-client-provider-C2CHH5x-.d.ts} +1 -1
- package/dist/{do-oauth-client-provider-CswoD5Lu.js → do-oauth-client-provider-CwqK5SXm.js} +2 -1
- package/dist/do-oauth-client-provider-CwqK5SXm.js.map +1 -0
- package/dist/{index-DhJCaDWd.d.ts → index-BUle9RiP.d.ts} +2 -2
- package/dist/{index-DEZFuVoU.d.ts → index-Bx5KK3VJ.d.ts} +44 -23
- package/dist/index.d.ts +6 -6
- package/dist/index.js +5 -5
- package/dist/mcp/client.d.ts +4 -4
- package/dist/mcp/client.js +2 -1
- package/dist/mcp/do-oauth-client-provider.d.ts +1 -1
- package/dist/mcp/do-oauth-client-provider.js +1 -1
- package/dist/mcp/index.d.ts +11 -11
- package/dist/mcp/index.js +21 -14
- package/dist/mcp/index.js.map +1 -1
- package/dist/mcp/x402.js +10 -6
- package/dist/mcp/x402.js.map +1 -1
- package/dist/{mcp-Dw5vDrY8.d.ts → mcp-BwPscEiF.d.ts} +1 -1
- package/dist/observability/index.d.ts +2 -2
- package/dist/observability/index.js +5 -5
- package/dist/{react-CrV9uP64.d.ts → react-CbwD4fBf.d.ts} +4 -4
- package/dist/react.d.ts +9 -9
- package/dist/react.js +2 -2
- package/dist/react.js.map +1 -1
- package/dist/{serializable-CymX8ovI.d.ts → serializable-faDkMCai.d.ts} +1 -1
- package/dist/serializable.d.ts +1 -1
- package/dist/{src-C8K3lu37.js → src-D_KKH_4c.js} +99 -146
- package/dist/src-D_KKH_4c.js.map +1 -0
- package/package.json +7 -7
- package/dist/ai-types-B3aQaFv3.js.map +0 -1
- package/dist/client-DZhjV_XA.js +0 -719
- package/dist/client-DZhjV_XA.js.map +0 -1
- package/dist/client-GfgZTqrS.d.ts +0 -5283
- package/dist/do-oauth-client-provider-CswoD5Lu.js.map +0 -1
- package/dist/src-C8K3lu37.js.map +0 -1
package/dist/client-DZhjV_XA.js
DELETED
|
@@ -1,719 +0,0 @@
|
|
|
1
|
-
import { nanoid } from "nanoid";
|
|
2
|
-
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
3
|
-
import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
|
|
4
|
-
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
|
5
|
-
import { ElicitRequestSchema, PromptListChangedNotificationSchema, ResourceListChangedNotificationSchema, ToolListChangedNotificationSchema } from "@modelcontextprotocol/sdk/types.js";
|
|
6
|
-
|
|
7
|
-
//#region src/core/events.ts
|
|
8
|
-
function toDisposable(fn) {
|
|
9
|
-
return { dispose: fn };
|
|
10
|
-
}
|
|
11
|
-
var DisposableStore = class {
|
|
12
|
-
constructor() {
|
|
13
|
-
this._items = [];
|
|
14
|
-
}
|
|
15
|
-
add(d) {
|
|
16
|
-
this._items.push(d);
|
|
17
|
-
return d;
|
|
18
|
-
}
|
|
19
|
-
dispose() {
|
|
20
|
-
while (this._items.length) try {
|
|
21
|
-
this._items.pop().dispose();
|
|
22
|
-
} catch {}
|
|
23
|
-
}
|
|
24
|
-
};
|
|
25
|
-
var Emitter = class {
|
|
26
|
-
constructor() {
|
|
27
|
-
this._listeners = /* @__PURE__ */ new Set();
|
|
28
|
-
this.event = (listener) => {
|
|
29
|
-
this._listeners.add(listener);
|
|
30
|
-
return toDisposable(() => this._listeners.delete(listener));
|
|
31
|
-
};
|
|
32
|
-
}
|
|
33
|
-
fire(data) {
|
|
34
|
-
for (const listener of [...this._listeners]) try {
|
|
35
|
-
listener(data);
|
|
36
|
-
} catch (err) {
|
|
37
|
-
console.error("Emitter listener error:", err);
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
dispose() {
|
|
41
|
-
this._listeners.clear();
|
|
42
|
-
}
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
//#endregion
|
|
46
|
-
//#region src/mcp/errors.ts
|
|
47
|
-
function toErrorMessage(error) {
|
|
48
|
-
return error instanceof Error ? error.message : String(error);
|
|
49
|
-
}
|
|
50
|
-
function isUnauthorized(error) {
|
|
51
|
-
const msg = toErrorMessage(error);
|
|
52
|
-
return msg.includes("Unauthorized") || msg.includes("401");
|
|
53
|
-
}
|
|
54
|
-
function isTransportNotImplemented(error) {
|
|
55
|
-
const msg = toErrorMessage(error);
|
|
56
|
-
return msg.includes("404") || msg.includes("405") || msg.includes("Not Implemented") || msg.includes("not implemented");
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
//#endregion
|
|
60
|
-
//#region src/mcp/client-connection.ts
|
|
61
|
-
var MCPClientConnection = class {
|
|
62
|
-
constructor(url, info, options = {
|
|
63
|
-
client: {},
|
|
64
|
-
transport: {}
|
|
65
|
-
}) {
|
|
66
|
-
this.url = url;
|
|
67
|
-
this.options = options;
|
|
68
|
-
this.connectionState = "connecting";
|
|
69
|
-
this.tools = [];
|
|
70
|
-
this.prompts = [];
|
|
71
|
-
this.resources = [];
|
|
72
|
-
this.resourceTemplates = [];
|
|
73
|
-
this._onObservabilityEvent = new Emitter();
|
|
74
|
-
this.onObservabilityEvent = this._onObservabilityEvent.event;
|
|
75
|
-
this.client = new Client(info, {
|
|
76
|
-
...options.client,
|
|
77
|
-
capabilities: {
|
|
78
|
-
...options.client?.capabilities,
|
|
79
|
-
elicitation: {}
|
|
80
|
-
}
|
|
81
|
-
});
|
|
82
|
-
}
|
|
83
|
-
/**
|
|
84
|
-
* Initialize a client connection
|
|
85
|
-
*
|
|
86
|
-
* @returns
|
|
87
|
-
*/
|
|
88
|
-
async init() {
|
|
89
|
-
const transportType = this.options.transport.type;
|
|
90
|
-
if (!transportType) throw new Error("Transport type must be specified");
|
|
91
|
-
try {
|
|
92
|
-
await this.tryConnect(transportType);
|
|
93
|
-
} catch (e) {
|
|
94
|
-
if (isUnauthorized(e)) {
|
|
95
|
-
this.connectionState = "authenticating";
|
|
96
|
-
return;
|
|
97
|
-
}
|
|
98
|
-
this._onObservabilityEvent.fire({
|
|
99
|
-
type: "mcp:client:connect",
|
|
100
|
-
displayMessage: `Connection initialization failed for ${this.url.toString()}`,
|
|
101
|
-
payload: {
|
|
102
|
-
url: this.url.toString(),
|
|
103
|
-
transport: transportType,
|
|
104
|
-
state: this.connectionState,
|
|
105
|
-
error: toErrorMessage(e)
|
|
106
|
-
},
|
|
107
|
-
timestamp: Date.now(),
|
|
108
|
-
id: nanoid()
|
|
109
|
-
});
|
|
110
|
-
this.connectionState = "failed";
|
|
111
|
-
return;
|
|
112
|
-
}
|
|
113
|
-
await this.discoverAndRegister();
|
|
114
|
-
}
|
|
115
|
-
/**
|
|
116
|
-
* Finish OAuth by probing transports based on configured type.
|
|
117
|
-
* - Explicit: finish on that transport
|
|
118
|
-
* - Auto: try streamable-http, then sse on 404/405/Not Implemented
|
|
119
|
-
*/
|
|
120
|
-
async finishAuthProbe(code) {
|
|
121
|
-
if (!this.options.transport.authProvider) throw new Error("No auth provider configured");
|
|
122
|
-
const configuredType = this.options.transport.type;
|
|
123
|
-
if (!configuredType) throw new Error("Transport type must be specified");
|
|
124
|
-
const finishAuth = async (base) => {
|
|
125
|
-
await this.getTransport(base).finishAuth(code);
|
|
126
|
-
};
|
|
127
|
-
if (configuredType === "sse" || configuredType === "streamable-http") {
|
|
128
|
-
await finishAuth(configuredType);
|
|
129
|
-
return;
|
|
130
|
-
}
|
|
131
|
-
try {
|
|
132
|
-
await finishAuth("streamable-http");
|
|
133
|
-
} catch (e) {
|
|
134
|
-
if (isTransportNotImplemented(e)) {
|
|
135
|
-
await finishAuth("sse");
|
|
136
|
-
return;
|
|
137
|
-
}
|
|
138
|
-
throw e;
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
/**
|
|
142
|
-
* Complete OAuth authorization
|
|
143
|
-
*/
|
|
144
|
-
async completeAuthorization(code) {
|
|
145
|
-
if (this.connectionState !== "authenticating") throw new Error("Connection must be in authenticating state to complete authorization");
|
|
146
|
-
try {
|
|
147
|
-
await this.finishAuthProbe(code);
|
|
148
|
-
this.connectionState = "connecting";
|
|
149
|
-
} catch (error) {
|
|
150
|
-
this.connectionState = "failed";
|
|
151
|
-
throw error;
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
/**
|
|
155
|
-
* Establish connection after successful authorization
|
|
156
|
-
*/
|
|
157
|
-
async establishConnection() {
|
|
158
|
-
if (this.connectionState !== "connecting") throw new Error("Connection must be in connecting state to establish connection");
|
|
159
|
-
try {
|
|
160
|
-
const transportType = this.options.transport.type;
|
|
161
|
-
if (!transportType) throw new Error("Transport type must be specified");
|
|
162
|
-
await this.tryConnect(transportType);
|
|
163
|
-
await this.discoverAndRegister();
|
|
164
|
-
} catch (error) {
|
|
165
|
-
this.connectionState = "failed";
|
|
166
|
-
throw error;
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
/**
|
|
170
|
-
* Discover server capabilities and register tools, resources, prompts, and templates
|
|
171
|
-
*/
|
|
172
|
-
async discoverAndRegister() {
|
|
173
|
-
this.connectionState = "discovering";
|
|
174
|
-
this.serverCapabilities = this.client.getServerCapabilities();
|
|
175
|
-
if (!this.serverCapabilities) throw new Error("The MCP Server failed to return server capabilities");
|
|
176
|
-
const [instructionsResult, toolsResult, resourcesResult, promptsResult, resourceTemplatesResult] = await Promise.allSettled([
|
|
177
|
-
this.client.getInstructions(),
|
|
178
|
-
this.registerTools(),
|
|
179
|
-
this.registerResources(),
|
|
180
|
-
this.registerPrompts(),
|
|
181
|
-
this.registerResourceTemplates()
|
|
182
|
-
]);
|
|
183
|
-
const operations = [
|
|
184
|
-
{
|
|
185
|
-
name: "instructions",
|
|
186
|
-
result: instructionsResult
|
|
187
|
-
},
|
|
188
|
-
{
|
|
189
|
-
name: "tools",
|
|
190
|
-
result: toolsResult
|
|
191
|
-
},
|
|
192
|
-
{
|
|
193
|
-
name: "resources",
|
|
194
|
-
result: resourcesResult
|
|
195
|
-
},
|
|
196
|
-
{
|
|
197
|
-
name: "prompts",
|
|
198
|
-
result: promptsResult
|
|
199
|
-
},
|
|
200
|
-
{
|
|
201
|
-
name: "resource templates",
|
|
202
|
-
result: resourceTemplatesResult
|
|
203
|
-
}
|
|
204
|
-
];
|
|
205
|
-
for (const { name, result } of operations) if (result.status === "rejected") {
|
|
206
|
-
const url = this.url.toString();
|
|
207
|
-
this._onObservabilityEvent.fire({
|
|
208
|
-
type: "mcp:client:discover",
|
|
209
|
-
displayMessage: `Failed to discover ${name} for ${url}`,
|
|
210
|
-
payload: {
|
|
211
|
-
url,
|
|
212
|
-
capability: name,
|
|
213
|
-
error: result.reason
|
|
214
|
-
},
|
|
215
|
-
timestamp: Date.now(),
|
|
216
|
-
id: nanoid()
|
|
217
|
-
});
|
|
218
|
-
}
|
|
219
|
-
this.instructions = instructionsResult.status === "fulfilled" ? instructionsResult.value : void 0;
|
|
220
|
-
this.tools = toolsResult.status === "fulfilled" ? toolsResult.value : [];
|
|
221
|
-
this.resources = resourcesResult.status === "fulfilled" ? resourcesResult.value : [];
|
|
222
|
-
this.prompts = promptsResult.status === "fulfilled" ? promptsResult.value : [];
|
|
223
|
-
this.resourceTemplates = resourceTemplatesResult.status === "fulfilled" ? resourceTemplatesResult.value : [];
|
|
224
|
-
this.connectionState = "ready";
|
|
225
|
-
}
|
|
226
|
-
/**
|
|
227
|
-
* Notification handler registration
|
|
228
|
-
*/
|
|
229
|
-
async registerTools() {
|
|
230
|
-
if (!this.serverCapabilities || !this.serverCapabilities.tools) return [];
|
|
231
|
-
if (this.serverCapabilities.tools.listChanged) this.client.setNotificationHandler(ToolListChangedNotificationSchema, async (_notification) => {
|
|
232
|
-
this.tools = await this.fetchTools();
|
|
233
|
-
});
|
|
234
|
-
return this.fetchTools();
|
|
235
|
-
}
|
|
236
|
-
async registerResources() {
|
|
237
|
-
if (!this.serverCapabilities || !this.serverCapabilities.resources) return [];
|
|
238
|
-
if (this.serverCapabilities.resources.listChanged) this.client.setNotificationHandler(ResourceListChangedNotificationSchema, async (_notification) => {
|
|
239
|
-
this.resources = await this.fetchResources();
|
|
240
|
-
});
|
|
241
|
-
return this.fetchResources();
|
|
242
|
-
}
|
|
243
|
-
async registerPrompts() {
|
|
244
|
-
if (!this.serverCapabilities || !this.serverCapabilities.prompts) return [];
|
|
245
|
-
if (this.serverCapabilities.prompts.listChanged) this.client.setNotificationHandler(PromptListChangedNotificationSchema, async (_notification) => {
|
|
246
|
-
this.prompts = await this.fetchPrompts();
|
|
247
|
-
});
|
|
248
|
-
return this.fetchPrompts();
|
|
249
|
-
}
|
|
250
|
-
async registerResourceTemplates() {
|
|
251
|
-
if (!this.serverCapabilities || !this.serverCapabilities.resources) return [];
|
|
252
|
-
return this.fetchResourceTemplates();
|
|
253
|
-
}
|
|
254
|
-
async fetchTools() {
|
|
255
|
-
let toolsAgg = [];
|
|
256
|
-
let toolsResult = { tools: [] };
|
|
257
|
-
do {
|
|
258
|
-
toolsResult = await this.client.listTools({ cursor: toolsResult.nextCursor }).catch(this._capabilityErrorHandler({ tools: [] }, "tools/list"));
|
|
259
|
-
toolsAgg = toolsAgg.concat(toolsResult.tools);
|
|
260
|
-
} while (toolsResult.nextCursor);
|
|
261
|
-
return toolsAgg;
|
|
262
|
-
}
|
|
263
|
-
async fetchResources() {
|
|
264
|
-
let resourcesAgg = [];
|
|
265
|
-
let resourcesResult = { resources: [] };
|
|
266
|
-
do {
|
|
267
|
-
resourcesResult = await this.client.listResources({ cursor: resourcesResult.nextCursor }).catch(this._capabilityErrorHandler({ resources: [] }, "resources/list"));
|
|
268
|
-
resourcesAgg = resourcesAgg.concat(resourcesResult.resources);
|
|
269
|
-
} while (resourcesResult.nextCursor);
|
|
270
|
-
return resourcesAgg;
|
|
271
|
-
}
|
|
272
|
-
async fetchPrompts() {
|
|
273
|
-
let promptsAgg = [];
|
|
274
|
-
let promptsResult = { prompts: [] };
|
|
275
|
-
do {
|
|
276
|
-
promptsResult = await this.client.listPrompts({ cursor: promptsResult.nextCursor }).catch(this._capabilityErrorHandler({ prompts: [] }, "prompts/list"));
|
|
277
|
-
promptsAgg = promptsAgg.concat(promptsResult.prompts);
|
|
278
|
-
} while (promptsResult.nextCursor);
|
|
279
|
-
return promptsAgg;
|
|
280
|
-
}
|
|
281
|
-
async fetchResourceTemplates() {
|
|
282
|
-
let templatesAgg = [];
|
|
283
|
-
let templatesResult = { resourceTemplates: [] };
|
|
284
|
-
do {
|
|
285
|
-
templatesResult = await this.client.listResourceTemplates({ cursor: templatesResult.nextCursor }).catch(this._capabilityErrorHandler({ resourceTemplates: [] }, "resources/templates/list"));
|
|
286
|
-
templatesAgg = templatesAgg.concat(templatesResult.resourceTemplates);
|
|
287
|
-
} while (templatesResult.nextCursor);
|
|
288
|
-
return templatesAgg;
|
|
289
|
-
}
|
|
290
|
-
/**
|
|
291
|
-
* Handle elicitation request from server
|
|
292
|
-
* Automatically uses the Agent's built-in elicitation handling if available
|
|
293
|
-
*/
|
|
294
|
-
async handleElicitationRequest(_request) {
|
|
295
|
-
throw new Error("Elicitation handler must be implemented for your platform. Override handleElicitationRequest method.");
|
|
296
|
-
}
|
|
297
|
-
/**
|
|
298
|
-
* Get the transport for the client
|
|
299
|
-
* @param transportType - The transport type to get
|
|
300
|
-
* @returns The transport for the client
|
|
301
|
-
*/
|
|
302
|
-
getTransport(transportType) {
|
|
303
|
-
switch (transportType) {
|
|
304
|
-
case "streamable-http": return new StreamableHTTPClientTransport(this.url, this.options.transport);
|
|
305
|
-
case "sse": return new SSEClientTransport(this.url, this.options.transport);
|
|
306
|
-
default: throw new Error(`Unsupported transport type: ${transportType}`);
|
|
307
|
-
}
|
|
308
|
-
}
|
|
309
|
-
async tryConnect(transportType) {
|
|
310
|
-
const transports = transportType === "auto" ? ["streamable-http", "sse"] : [transportType];
|
|
311
|
-
for (const currentTransportType of transports) {
|
|
312
|
-
const isLastTransport = currentTransportType === transports[transports.length - 1];
|
|
313
|
-
const hasFallback = transportType === "auto" && currentTransportType === "streamable-http" && !isLastTransport;
|
|
314
|
-
const transport = this.getTransport(currentTransportType);
|
|
315
|
-
try {
|
|
316
|
-
await this.client.connect(transport);
|
|
317
|
-
this.lastConnectedTransport = currentTransportType;
|
|
318
|
-
const url = this.url.toString();
|
|
319
|
-
this._onObservabilityEvent.fire({
|
|
320
|
-
type: "mcp:client:connect",
|
|
321
|
-
displayMessage: `Connected successfully using ${currentTransportType} transport for ${url}`,
|
|
322
|
-
payload: {
|
|
323
|
-
url,
|
|
324
|
-
transport: currentTransportType,
|
|
325
|
-
state: this.connectionState
|
|
326
|
-
},
|
|
327
|
-
timestamp: Date.now(),
|
|
328
|
-
id: nanoid()
|
|
329
|
-
});
|
|
330
|
-
break;
|
|
331
|
-
} catch (e) {
|
|
332
|
-
const error = e instanceof Error ? e : new Error(String(e));
|
|
333
|
-
if (isUnauthorized(error)) throw e;
|
|
334
|
-
if (hasFallback && isTransportNotImplemented(error)) {
|
|
335
|
-
const url = this.url.toString();
|
|
336
|
-
this._onObservabilityEvent.fire({
|
|
337
|
-
type: "mcp:client:connect",
|
|
338
|
-
displayMessage: `${currentTransportType} transport not available, trying ${transports[transports.indexOf(currentTransportType) + 1]} for ${url}`,
|
|
339
|
-
payload: {
|
|
340
|
-
url,
|
|
341
|
-
transport: currentTransportType,
|
|
342
|
-
state: this.connectionState
|
|
343
|
-
},
|
|
344
|
-
timestamp: Date.now(),
|
|
345
|
-
id: nanoid()
|
|
346
|
-
});
|
|
347
|
-
continue;
|
|
348
|
-
}
|
|
349
|
-
throw e;
|
|
350
|
-
}
|
|
351
|
-
}
|
|
352
|
-
this.client.setRequestHandler(ElicitRequestSchema, async (request) => {
|
|
353
|
-
return await this.handleElicitationRequest(request);
|
|
354
|
-
});
|
|
355
|
-
}
|
|
356
|
-
_capabilityErrorHandler(empty, method) {
|
|
357
|
-
return (e) => {
|
|
358
|
-
if (e.code === -32601) {
|
|
359
|
-
const url = this.url.toString();
|
|
360
|
-
this._onObservabilityEvent.fire({
|
|
361
|
-
type: "mcp:client:discover",
|
|
362
|
-
displayMessage: `The server advertised support for the capability ${method.split("/")[0]}, but returned "Method not found" for '${method}' for ${url}`,
|
|
363
|
-
payload: {
|
|
364
|
-
url,
|
|
365
|
-
capability: method.split("/")[0],
|
|
366
|
-
error: toErrorMessage(e)
|
|
367
|
-
},
|
|
368
|
-
timestamp: Date.now(),
|
|
369
|
-
id: nanoid()
|
|
370
|
-
});
|
|
371
|
-
return empty;
|
|
372
|
-
}
|
|
373
|
-
throw e;
|
|
374
|
-
};
|
|
375
|
-
}
|
|
376
|
-
};
|
|
377
|
-
|
|
378
|
-
//#endregion
|
|
379
|
-
//#region src/mcp/client.ts
|
|
380
|
-
/**
|
|
381
|
-
* Utility class that aggregates multiple MCP clients into one
|
|
382
|
-
*/
|
|
383
|
-
var MCPClientManager = class {
|
|
384
|
-
/**
|
|
385
|
-
* @param _name Name of the MCP client
|
|
386
|
-
* @param _version Version of the MCP Client
|
|
387
|
-
* @param auth Auth paramters if being used to create a DurableObjectOAuthClientProvider
|
|
388
|
-
*/
|
|
389
|
-
constructor(_name, _version) {
|
|
390
|
-
this._name = _name;
|
|
391
|
-
this._version = _version;
|
|
392
|
-
this.mcpConnections = {};
|
|
393
|
-
this._callbackUrls = [];
|
|
394
|
-
this._didWarnAboutUnstableGetAITools = false;
|
|
395
|
-
this._connectionDisposables = /* @__PURE__ */ new Map();
|
|
396
|
-
this._onObservabilityEvent = new Emitter();
|
|
397
|
-
this.onObservabilityEvent = this._onObservabilityEvent.event;
|
|
398
|
-
this._onConnected = new Emitter();
|
|
399
|
-
this.onConnected = this._onConnected.event;
|
|
400
|
-
}
|
|
401
|
-
/**
|
|
402
|
-
* Connect to and register an MCP server
|
|
403
|
-
*
|
|
404
|
-
* @param transportConfig Transport config
|
|
405
|
-
* @param clientConfig Client config
|
|
406
|
-
* @param capabilities Client capabilities (i.e. if the client supports roots/sampling)
|
|
407
|
-
*/
|
|
408
|
-
async connect(url, options = {}) {
|
|
409
|
-
/**
|
|
410
|
-
* We need to delay loading ai sdk, because putting it in module scope is
|
|
411
|
-
* causing issues with startup time.
|
|
412
|
-
* The only place it's used is in getAITools, which only matters after
|
|
413
|
-
* .connect() is called on at least one server.
|
|
414
|
-
* So it's safe to delay loading it until .connect() is called.
|
|
415
|
-
*/
|
|
416
|
-
if (!this.jsonSchema) {
|
|
417
|
-
const { jsonSchema } = await import("ai");
|
|
418
|
-
this.jsonSchema = jsonSchema;
|
|
419
|
-
}
|
|
420
|
-
const id = options.reconnect?.id ?? nanoid(8);
|
|
421
|
-
if (options.transport?.authProvider) {
|
|
422
|
-
options.transport.authProvider.serverId = id;
|
|
423
|
-
if (options.reconnect?.oauthClientId) options.transport.authProvider.clientId = options.reconnect?.oauthClientId;
|
|
424
|
-
}
|
|
425
|
-
if (!options.reconnect?.oauthCode || !this.mcpConnections[id]) {
|
|
426
|
-
const normalizedTransport = {
|
|
427
|
-
...options.transport,
|
|
428
|
-
type: options.transport?.type ?? "auto"
|
|
429
|
-
};
|
|
430
|
-
this.mcpConnections[id] = new MCPClientConnection(new URL(url), {
|
|
431
|
-
name: this._name,
|
|
432
|
-
version: this._version
|
|
433
|
-
}, {
|
|
434
|
-
client: options.client ?? {},
|
|
435
|
-
transport: normalizedTransport
|
|
436
|
-
});
|
|
437
|
-
const store = new DisposableStore();
|
|
438
|
-
const existing = this._connectionDisposables.get(id);
|
|
439
|
-
if (existing) existing.dispose();
|
|
440
|
-
this._connectionDisposables.set(id, store);
|
|
441
|
-
store.add(this.mcpConnections[id].onObservabilityEvent((event) => {
|
|
442
|
-
this._onObservabilityEvent.fire(event);
|
|
443
|
-
}));
|
|
444
|
-
}
|
|
445
|
-
await this.mcpConnections[id].init();
|
|
446
|
-
if (options.reconnect?.oauthCode) try {
|
|
447
|
-
await this.mcpConnections[id].completeAuthorization(options.reconnect.oauthCode);
|
|
448
|
-
await this.mcpConnections[id].establishConnection();
|
|
449
|
-
} catch (error) {
|
|
450
|
-
this._onObservabilityEvent.fire({
|
|
451
|
-
type: "mcp:client:connect",
|
|
452
|
-
displayMessage: `Failed to complete OAuth reconnection for ${id} for ${url}`,
|
|
453
|
-
payload: {
|
|
454
|
-
url,
|
|
455
|
-
transport: options.transport?.type ?? "auto",
|
|
456
|
-
state: this.mcpConnections[id].connectionState,
|
|
457
|
-
error: toErrorMessage(error)
|
|
458
|
-
},
|
|
459
|
-
timestamp: Date.now(),
|
|
460
|
-
id
|
|
461
|
-
});
|
|
462
|
-
throw error;
|
|
463
|
-
}
|
|
464
|
-
const authUrl = options.transport?.authProvider?.authUrl;
|
|
465
|
-
if (this.mcpConnections[id].connectionState === "authenticating" && authUrl && options.transport?.authProvider?.redirectUrl) {
|
|
466
|
-
this._callbackUrls.push(options.transport.authProvider.redirectUrl.toString());
|
|
467
|
-
return {
|
|
468
|
-
authUrl,
|
|
469
|
-
clientId: options.transport?.authProvider?.clientId,
|
|
470
|
-
id
|
|
471
|
-
};
|
|
472
|
-
}
|
|
473
|
-
return { id };
|
|
474
|
-
}
|
|
475
|
-
isCallbackRequest(req) {
|
|
476
|
-
return req.method === "GET" && !!this._callbackUrls.find((url) => {
|
|
477
|
-
return req.url.startsWith(url);
|
|
478
|
-
});
|
|
479
|
-
}
|
|
480
|
-
async handleCallbackRequest(req) {
|
|
481
|
-
const url = new URL(req.url);
|
|
482
|
-
const urlMatch = this._callbackUrls.find((url$1) => {
|
|
483
|
-
return req.url.startsWith(url$1);
|
|
484
|
-
});
|
|
485
|
-
if (!urlMatch) throw new Error(`No callback URI match found for the request url: ${req.url}. Was the request matched with \`isCallbackRequest()\`?`);
|
|
486
|
-
const code = url.searchParams.get("code");
|
|
487
|
-
const state = url.searchParams.get("state");
|
|
488
|
-
const error = url.searchParams.get("error");
|
|
489
|
-
const errorDescription = url.searchParams.get("error_description");
|
|
490
|
-
const urlParams = urlMatch.split("/");
|
|
491
|
-
const serverId = urlParams[urlParams.length - 1];
|
|
492
|
-
if (error) return {
|
|
493
|
-
serverId,
|
|
494
|
-
authSuccess: false,
|
|
495
|
-
authError: errorDescription || error
|
|
496
|
-
};
|
|
497
|
-
if (!code) throw new Error("Unauthorized: no code provided");
|
|
498
|
-
if (!state) throw new Error("Unauthorized: no state provided");
|
|
499
|
-
if (this.mcpConnections[serverId] === void 0) throw new Error(`Could not find serverId: ${serverId}`);
|
|
500
|
-
if (this.mcpConnections[serverId].connectionState !== "authenticating") throw new Error("Failed to authenticate: the client isn't in the `authenticating` state");
|
|
501
|
-
const conn = this.mcpConnections[serverId];
|
|
502
|
-
if (!conn.options.transport.authProvider) throw new Error("Trying to finalize authentication for a server connection without an authProvider");
|
|
503
|
-
const clientId = conn.options.transport.authProvider.clientId || state;
|
|
504
|
-
conn.options.transport.authProvider.clientId = clientId;
|
|
505
|
-
conn.options.transport.authProvider.serverId = serverId;
|
|
506
|
-
try {
|
|
507
|
-
await conn.completeAuthorization(code);
|
|
508
|
-
return {
|
|
509
|
-
serverId,
|
|
510
|
-
authSuccess: true
|
|
511
|
-
};
|
|
512
|
-
} catch (error$1) {
|
|
513
|
-
return {
|
|
514
|
-
serverId,
|
|
515
|
-
authSuccess: false,
|
|
516
|
-
authError: error$1 instanceof Error ? error$1.message : String(error$1)
|
|
517
|
-
};
|
|
518
|
-
}
|
|
519
|
-
}
|
|
520
|
-
/**
|
|
521
|
-
* Establish connection in the background after OAuth completion
|
|
522
|
-
* This method is called asynchronously and doesn't block the OAuth callback response
|
|
523
|
-
* @param serverId The server ID to establish connection for
|
|
524
|
-
*/
|
|
525
|
-
async establishConnection(serverId) {
|
|
526
|
-
const conn = this.mcpConnections[serverId];
|
|
527
|
-
if (!conn) {
|
|
528
|
-
this._onObservabilityEvent.fire({
|
|
529
|
-
type: "mcp:client:preconnect",
|
|
530
|
-
displayMessage: `Connection not found for serverId: ${serverId}`,
|
|
531
|
-
payload: { serverId },
|
|
532
|
-
timestamp: Date.now(),
|
|
533
|
-
id: nanoid()
|
|
534
|
-
});
|
|
535
|
-
return;
|
|
536
|
-
}
|
|
537
|
-
try {
|
|
538
|
-
await conn.establishConnection();
|
|
539
|
-
this._onConnected.fire(serverId);
|
|
540
|
-
} catch (error) {
|
|
541
|
-
const url = conn.url.toString();
|
|
542
|
-
this._onObservabilityEvent.fire({
|
|
543
|
-
type: "mcp:client:connect",
|
|
544
|
-
displayMessage: `Failed to establish connection to server ${serverId} with url ${url}`,
|
|
545
|
-
payload: {
|
|
546
|
-
url,
|
|
547
|
-
transport: conn.options.transport.type ?? "auto",
|
|
548
|
-
state: conn.connectionState,
|
|
549
|
-
error: toErrorMessage(error)
|
|
550
|
-
},
|
|
551
|
-
timestamp: Date.now(),
|
|
552
|
-
id: nanoid()
|
|
553
|
-
});
|
|
554
|
-
}
|
|
555
|
-
}
|
|
556
|
-
/**
|
|
557
|
-
* Register a callback URL for OAuth handling
|
|
558
|
-
* @param url The callback URL to register
|
|
559
|
-
*/
|
|
560
|
-
registerCallbackUrl(url) {
|
|
561
|
-
if (!this._callbackUrls.includes(url)) this._callbackUrls.push(url);
|
|
562
|
-
}
|
|
563
|
-
/**
|
|
564
|
-
* Unregister a callback URL
|
|
565
|
-
* @param serverId The server ID whose callback URL should be removed
|
|
566
|
-
*/
|
|
567
|
-
unregisterCallbackUrl(serverId) {
|
|
568
|
-
this._callbackUrls = this._callbackUrls.filter((url) => !url.endsWith(`/${serverId}`));
|
|
569
|
-
}
|
|
570
|
-
/**
|
|
571
|
-
* Configure OAuth callback handling
|
|
572
|
-
* @param config OAuth callback configuration
|
|
573
|
-
*/
|
|
574
|
-
configureOAuthCallback(config) {
|
|
575
|
-
this._oauthCallbackConfig = config;
|
|
576
|
-
}
|
|
577
|
-
/**
|
|
578
|
-
* Get the current OAuth callback configuration
|
|
579
|
-
* @returns The current OAuth callback configuration
|
|
580
|
-
*/
|
|
581
|
-
getOAuthCallbackConfig() {
|
|
582
|
-
return this._oauthCallbackConfig;
|
|
583
|
-
}
|
|
584
|
-
/**
|
|
585
|
-
* @returns namespaced list of tools
|
|
586
|
-
*/
|
|
587
|
-
listTools() {
|
|
588
|
-
return getNamespacedData(this.mcpConnections, "tools");
|
|
589
|
-
}
|
|
590
|
-
/**
|
|
591
|
-
* @returns a set of tools that you can use with the AI SDK
|
|
592
|
-
*/
|
|
593
|
-
getAITools() {
|
|
594
|
-
return Object.fromEntries(getNamespacedData(this.mcpConnections, "tools").map((tool) => {
|
|
595
|
-
return [`tool_${tool.serverId.replace(/-/g, "")}_${tool.name}`, {
|
|
596
|
-
description: tool.description,
|
|
597
|
-
execute: async (args) => {
|
|
598
|
-
const result = await this.callTool({
|
|
599
|
-
arguments: args,
|
|
600
|
-
name: tool.name,
|
|
601
|
-
serverId: tool.serverId
|
|
602
|
-
});
|
|
603
|
-
if (result.isError) throw new Error(result.content[0].text);
|
|
604
|
-
return result;
|
|
605
|
-
},
|
|
606
|
-
inputSchema: this.jsonSchema(tool.inputSchema),
|
|
607
|
-
outputSchema: tool.outputSchema ? this.jsonSchema(tool.outputSchema) : void 0
|
|
608
|
-
}];
|
|
609
|
-
}));
|
|
610
|
-
}
|
|
611
|
-
/**
|
|
612
|
-
* @deprecated this has been renamed to getAITools(), and unstable_getAITools will be removed in the next major version
|
|
613
|
-
* @returns a set of tools that you can use with the AI SDK
|
|
614
|
-
*/
|
|
615
|
-
unstable_getAITools() {
|
|
616
|
-
if (!this._didWarnAboutUnstableGetAITools) {
|
|
617
|
-
this._didWarnAboutUnstableGetAITools = true;
|
|
618
|
-
console.warn("unstable_getAITools is deprecated, use getAITools instead. unstable_getAITools will be removed in the next major version.");
|
|
619
|
-
}
|
|
620
|
-
return this.getAITools();
|
|
621
|
-
}
|
|
622
|
-
/**
|
|
623
|
-
* Closes all connections to MCP servers
|
|
624
|
-
*/
|
|
625
|
-
async closeAllConnections() {
|
|
626
|
-
const ids = Object.keys(this.mcpConnections);
|
|
627
|
-
await Promise.all(ids.map(async (id) => {
|
|
628
|
-
await this.mcpConnections[id].client.close();
|
|
629
|
-
}));
|
|
630
|
-
for (const id of ids) {
|
|
631
|
-
const store = this._connectionDisposables.get(id);
|
|
632
|
-
if (store) store.dispose();
|
|
633
|
-
this._connectionDisposables.delete(id);
|
|
634
|
-
delete this.mcpConnections[id];
|
|
635
|
-
}
|
|
636
|
-
}
|
|
637
|
-
/**
|
|
638
|
-
* Closes a connection to an MCP server
|
|
639
|
-
* @param id The id of the connection to close
|
|
640
|
-
*/
|
|
641
|
-
async closeConnection(id) {
|
|
642
|
-
if (!this.mcpConnections[id]) throw new Error(`Connection with id "${id}" does not exist.`);
|
|
643
|
-
await this.mcpConnections[id].client.close();
|
|
644
|
-
delete this.mcpConnections[id];
|
|
645
|
-
const store = this._connectionDisposables.get(id);
|
|
646
|
-
if (store) store.dispose();
|
|
647
|
-
this._connectionDisposables.delete(id);
|
|
648
|
-
}
|
|
649
|
-
/**
|
|
650
|
-
* Dispose the manager and all resources.
|
|
651
|
-
*/
|
|
652
|
-
async dispose() {
|
|
653
|
-
try {
|
|
654
|
-
await this.closeAllConnections();
|
|
655
|
-
} finally {
|
|
656
|
-
this._onConnected.dispose();
|
|
657
|
-
this._onObservabilityEvent.dispose();
|
|
658
|
-
}
|
|
659
|
-
}
|
|
660
|
-
/**
|
|
661
|
-
* @returns namespaced list of prompts
|
|
662
|
-
*/
|
|
663
|
-
listPrompts() {
|
|
664
|
-
return getNamespacedData(this.mcpConnections, "prompts");
|
|
665
|
-
}
|
|
666
|
-
/**
|
|
667
|
-
* @returns namespaced list of tools
|
|
668
|
-
*/
|
|
669
|
-
listResources() {
|
|
670
|
-
return getNamespacedData(this.mcpConnections, "resources");
|
|
671
|
-
}
|
|
672
|
-
/**
|
|
673
|
-
* @returns namespaced list of resource templates
|
|
674
|
-
*/
|
|
675
|
-
listResourceTemplates() {
|
|
676
|
-
return getNamespacedData(this.mcpConnections, "resourceTemplates");
|
|
677
|
-
}
|
|
678
|
-
/**
|
|
679
|
-
* Namespaced version of callTool
|
|
680
|
-
*/
|
|
681
|
-
async callTool(params, resultSchema, options) {
|
|
682
|
-
const unqualifiedName = params.name.replace(`${params.serverId}.`, "");
|
|
683
|
-
return this.mcpConnections[params.serverId].client.callTool({
|
|
684
|
-
...params,
|
|
685
|
-
name: unqualifiedName
|
|
686
|
-
}, resultSchema, options);
|
|
687
|
-
}
|
|
688
|
-
/**
|
|
689
|
-
* Namespaced version of readResource
|
|
690
|
-
*/
|
|
691
|
-
readResource(params, options) {
|
|
692
|
-
return this.mcpConnections[params.serverId].client.readResource(params, options);
|
|
693
|
-
}
|
|
694
|
-
/**
|
|
695
|
-
* Namespaced version of getPrompt
|
|
696
|
-
*/
|
|
697
|
-
getPrompt(params, options) {
|
|
698
|
-
return this.mcpConnections[params.serverId].client.getPrompt(params, options);
|
|
699
|
-
}
|
|
700
|
-
};
|
|
701
|
-
function getNamespacedData(mcpClients, type) {
|
|
702
|
-
return Object.entries(mcpClients).map(([name, conn]) => {
|
|
703
|
-
return {
|
|
704
|
-
data: conn[type],
|
|
705
|
-
name
|
|
706
|
-
};
|
|
707
|
-
}).flatMap(({ name: serverId, data }) => {
|
|
708
|
-
return data.map((item) => {
|
|
709
|
-
return {
|
|
710
|
-
...item,
|
|
711
|
-
serverId
|
|
712
|
-
};
|
|
713
|
-
});
|
|
714
|
-
});
|
|
715
|
-
}
|
|
716
|
-
|
|
717
|
-
//#endregion
|
|
718
|
-
export { DisposableStore as i, getNamespacedData as n, MCPClientConnection as r, MCPClientManager as t };
|
|
719
|
-
//# sourceMappingURL=client-DZhjV_XA.js.map
|