agents 0.19.0 → 0.20.0
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 +24 -19
- package/dist/{agent-tool-types-BNUGGBzQ.d.ts → agent-tool-types-Btk9ETS-.d.ts} +997 -356
- package/dist/agent-tool-types.d.ts +1 -1
- package/dist/{agent-tools-BFbzVLFc.d.ts → agent-tools-UuScsJg3.d.ts} +2 -2
- package/dist/agent-tools.d.ts +1 -1
- package/dist/browser/ai.js +1 -1
- package/dist/browser/index.js +1 -1
- package/dist/chat/index.d.ts +2 -2
- package/dist/chat-sdk/index.d.ts +1 -1
- package/dist/client-invoker-BNSZxAkv.d.ts +20 -0
- package/dist/client-invoker-VNZ7X0nn.js +57 -0
- package/dist/client-invoker-VNZ7X0nn.js.map +1 -0
- package/dist/{client-CcjiFpTf.js → client-zqKcsyFa.js} +434 -168
- package/dist/client-zqKcsyFa.js.map +1 -0
- package/dist/client.d.ts +1 -1
- package/dist/{connector-CdldGF3h.js → connector-KEJnl6e5.js} +2 -2
- package/dist/connector-KEJnl6e5.js.map +1 -0
- package/dist/{do-oauth-client-provider-D4ZwyBDu.d.ts → do-oauth-client-provider-VTZj2VtM.d.ts} +23 -11
- package/dist/experimental/webmcp.js +1 -1
- package/dist/handler-stateless-8hQN_kC3.js +367 -0
- package/dist/handler-stateless-8hQN_kC3.js.map +1 -0
- package/dist/handler-stateless-C_bo-Ytq.d.ts +107 -0
- package/dist/index.d.ts +12 -12
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/mcp/client.d.ts +22 -18
- package/dist/mcp/client.js +1 -1
- package/dist/mcp/do-oauth-client-provider.d.ts +1 -1
- package/dist/mcp/do-oauth-client-provider.js +25 -12
- package/dist/mcp/do-oauth-client-provider.js.map +1 -1
- package/dist/mcp/index.d.ts +48 -34
- package/dist/mcp/index.js +84 -79
- package/dist/mcp/index.js.map +1 -1
- package/dist/mcp/server.d.ts +17 -0
- package/dist/mcp/server.js +2 -0
- package/dist/mcp/x402.d.ts +21 -9
- package/dist/mcp/x402.js +8 -7
- package/dist/mcp/x402.js.map +1 -1
- package/dist/react.d.ts +1 -1
- package/dist/serializable.d.ts +1 -1
- package/dist/sub-routing.d.ts +6 -6
- package/dist/workflows.d.ts +1 -1
- package/docs/human-in-the-loop.md +63 -82
- package/docs/mcp-client.md +31 -7
- package/docs/mcp-servers.md +125 -88
- package/docs/securing-mcp-servers.md +9 -6
- package/package.json +28 -7
- package/dist/client-CcjiFpTf.js.map +0 -1
- package/dist/connector-CdldGF3h.js.map +0 -1
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
import { tryN } from "./retries.js";
|
|
2
|
+
import { n as callV2Tool } from "./client-invoker-VNZ7X0nn.js";
|
|
2
3
|
import { DurableObjectOAuthClientProvider } from "./mcp/do-oauth-client-provider.js";
|
|
3
4
|
import { nanoid } from "nanoid";
|
|
4
5
|
import { getServerByName } from "partyserver";
|
|
5
6
|
import { z } from "zod";
|
|
6
|
-
import { Client } from "@modelcontextprotocol/
|
|
7
|
-
import { CfWorkerJsonSchemaValidator } from "@modelcontextprotocol/
|
|
8
|
-
import {
|
|
9
|
-
import { StreamableHTTPClientTransport, StreamableHTTPError } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
|
10
|
-
import { ElicitRequestSchema, JSONRPCMessageSchema, PromptListChangedNotificationSchema, ResourceListChangedNotificationSchema, ToolListChangedNotificationSchema, isJSONRPCErrorResponse, isJSONRPCResultResponse } from "@modelcontextprotocol/sdk/types.js";
|
|
7
|
+
import { Client, SSEClientTransport, SdkHttpError, StreamableHTTPClientTransport } from "@modelcontextprotocol/client";
|
|
8
|
+
import { CfWorkerJsonSchemaValidator } from "@modelcontextprotocol/client/validators/cf-worker";
|
|
9
|
+
import { JSONRPCMessageSchema, isJSONRPCErrorResponse, isJSONRPCResultResponse } from "@modelcontextprotocol/sdk/types.js";
|
|
11
10
|
//#region src/core/events.ts
|
|
12
11
|
function toDisposable(fn) {
|
|
13
12
|
return { dispose: fn };
|
|
@@ -46,23 +45,187 @@ var Emitter = class {
|
|
|
46
45
|
}
|
|
47
46
|
};
|
|
48
47
|
//#endregion
|
|
48
|
+
//#region src/mcp/abort.ts
|
|
49
|
+
function abortError(signal) {
|
|
50
|
+
return signal.reason instanceof Error ? signal.reason : new Error(String(signal.reason ?? "Aborted"));
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Stop awaiting an operation when its owner aborts. The underlying operation
|
|
54
|
+
* remains responsible for observing the same signal and cancelling its work.
|
|
55
|
+
*/
|
|
56
|
+
async function raceWithSignal(promise, signal) {
|
|
57
|
+
if (!signal) return promise;
|
|
58
|
+
if (signal.aborted) throw abortError(signal);
|
|
59
|
+
return new Promise((resolve, reject) => {
|
|
60
|
+
const onAbort = () => reject(abortError(signal));
|
|
61
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
62
|
+
promise.then(resolve, reject).finally(() => {
|
|
63
|
+
signal.removeEventListener("abort", onAbort);
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
//#endregion
|
|
68
|
+
//#region src/mcp/client-catalog.ts
|
|
69
|
+
async function fetchMcpTools(client, options) {
|
|
70
|
+
let aggregate = [];
|
|
71
|
+
let page = { tools: [] };
|
|
72
|
+
do {
|
|
73
|
+
const params = { cursor: page.nextCursor };
|
|
74
|
+
page = await (options.probing ? client.request({
|
|
75
|
+
method: "tools/list",
|
|
76
|
+
params
|
|
77
|
+
}) : client.listTools(params)).catch(options.onCapabilityError({ tools: [] }, "tools/list"));
|
|
78
|
+
aggregate = aggregate.concat(page.tools);
|
|
79
|
+
} while (page.nextCursor);
|
|
80
|
+
return aggregate;
|
|
81
|
+
}
|
|
82
|
+
async function fetchMcpResources(client, options) {
|
|
83
|
+
let aggregate = [];
|
|
84
|
+
let page = { resources: [] };
|
|
85
|
+
do {
|
|
86
|
+
const params = { cursor: page.nextCursor };
|
|
87
|
+
page = await (options.probing ? client.request({
|
|
88
|
+
method: "resources/list",
|
|
89
|
+
params
|
|
90
|
+
}) : client.listResources(params)).catch(options.onCapabilityError({ resources: [] }, "resources/list"));
|
|
91
|
+
aggregate = aggregate.concat(page.resources);
|
|
92
|
+
} while (page.nextCursor);
|
|
93
|
+
return aggregate;
|
|
94
|
+
}
|
|
95
|
+
async function fetchMcpPrompts(client, options) {
|
|
96
|
+
let aggregate = [];
|
|
97
|
+
let page = { prompts: [] };
|
|
98
|
+
do {
|
|
99
|
+
const params = { cursor: page.nextCursor };
|
|
100
|
+
page = await (options.probing ? client.request({
|
|
101
|
+
method: "prompts/list",
|
|
102
|
+
params
|
|
103
|
+
}) : client.listPrompts(params)).catch(options.onCapabilityError({ prompts: [] }, "prompts/list"));
|
|
104
|
+
aggregate = aggregate.concat(page.prompts);
|
|
105
|
+
} while (page.nextCursor);
|
|
106
|
+
return aggregate;
|
|
107
|
+
}
|
|
108
|
+
async function fetchMcpResourceTemplates(client, options) {
|
|
109
|
+
let aggregate = [];
|
|
110
|
+
let page = { resourceTemplates: [] };
|
|
111
|
+
do {
|
|
112
|
+
const params = { cursor: page.nextCursor };
|
|
113
|
+
page = await (options.probing ? client.request({
|
|
114
|
+
method: "resources/templates/list",
|
|
115
|
+
params
|
|
116
|
+
}) : client.listResourceTemplates(params)).catch(options.onCapabilityError({ resourceTemplates: [] }, "resources/templates/list"));
|
|
117
|
+
aggregate = aggregate.concat(page.resourceTemplates);
|
|
118
|
+
} while (page.nextCursor);
|
|
119
|
+
return aggregate;
|
|
120
|
+
}
|
|
121
|
+
//#endregion
|
|
122
|
+
//#region src/mcp/client-runtime.ts
|
|
123
|
+
var CompatibleWorkerJsonSchemaValidator = class extends CfWorkerJsonSchemaValidator {
|
|
124
|
+
constructor(..._args) {
|
|
125
|
+
super(..._args);
|
|
126
|
+
this.legacy = new CfWorkerJsonSchemaValidator({ draft: "7" });
|
|
127
|
+
}
|
|
128
|
+
getValidator(schema) {
|
|
129
|
+
const dialect = schema.$schema;
|
|
130
|
+
return typeof dialect === "string" && /draft-0?7/i.test(dialect) ? this.legacy.getValidator(schema) : super.getValidator(schema);
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
const DEFAULT_CLIENT_OPTIONS = {
|
|
134
|
+
jsonSchemaValidator: new CompatibleWorkerJsonSchemaValidator(),
|
|
135
|
+
versionNegotiation: { mode: "auto" },
|
|
136
|
+
inputRequired: { autoFulfill: true }
|
|
137
|
+
};
|
|
138
|
+
function normalizeMcpClientOptions(options) {
|
|
139
|
+
return {
|
|
140
|
+
...DEFAULT_CLIENT_OPTIONS,
|
|
141
|
+
...options,
|
|
142
|
+
versionNegotiation: {
|
|
143
|
+
...DEFAULT_CLIENT_OPTIONS.versionNegotiation,
|
|
144
|
+
...options?.versionNegotiation
|
|
145
|
+
},
|
|
146
|
+
inputRequired: {
|
|
147
|
+
...DEFAULT_CLIENT_OPTIONS.inputRequired,
|
|
148
|
+
...options?.inputRequired
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
function elicitationCapabilitiesFromHandlers(handlers) {
|
|
153
|
+
if (!handlers) return void 0;
|
|
154
|
+
const elicitation = {};
|
|
155
|
+
if (handlers.form) elicitation.form = {};
|
|
156
|
+
if (handlers.url) elicitation.url = {};
|
|
157
|
+
return elicitation.form || elicitation.url ? elicitation : void 0;
|
|
158
|
+
}
|
|
159
|
+
function listChangedHandlers(configured, callbacks) {
|
|
160
|
+
return {
|
|
161
|
+
tools: {
|
|
162
|
+
...configured?.tools,
|
|
163
|
+
onChanged: (error, tools) => {
|
|
164
|
+
callbacks.tools(error, tools);
|
|
165
|
+
configured?.tools?.onChanged(error, tools);
|
|
166
|
+
}
|
|
167
|
+
},
|
|
168
|
+
prompts: {
|
|
169
|
+
...configured?.prompts,
|
|
170
|
+
onChanged: (error, prompts) => {
|
|
171
|
+
callbacks.prompts(error, prompts);
|
|
172
|
+
configured?.prompts?.onChanged(error, prompts);
|
|
173
|
+
}
|
|
174
|
+
},
|
|
175
|
+
resources: {
|
|
176
|
+
...configured?.resources,
|
|
177
|
+
onChanged: (error, resources) => {
|
|
178
|
+
callbacks.resources(error, resources);
|
|
179
|
+
configured?.resources?.onChanged(error, resources);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
function createMcpSdkClient(info, options, capabilitySeed, handlerModes, callbacks) {
|
|
185
|
+
const elicitation = options.capabilities?.elicitation ?? elicitationCapabilitiesFromHandlers(handlerModes) ?? capabilitySeed?.elicitation;
|
|
186
|
+
return {
|
|
187
|
+
client: new Client(info, {
|
|
188
|
+
...options,
|
|
189
|
+
capabilities: {
|
|
190
|
+
...capabilitySeed,
|
|
191
|
+
...options.capabilities,
|
|
192
|
+
...elicitation ? { elicitation } : {}
|
|
193
|
+
},
|
|
194
|
+
listChanged: listChangedHandlers(options.listChanged, callbacks)
|
|
195
|
+
}),
|
|
196
|
+
elicitationEnabled: elicitation !== void 0
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
//#endregion
|
|
49
200
|
//#region src/mcp/errors.ts
|
|
50
201
|
function toErrorMessage(error) {
|
|
51
202
|
return error instanceof Error ? error.message : String(error);
|
|
52
203
|
}
|
|
53
|
-
function
|
|
54
|
-
if (error
|
|
204
|
+
function getErrorStatus(error) {
|
|
205
|
+
if (!error || typeof error !== "object") return void 0;
|
|
206
|
+
const record = error;
|
|
207
|
+
if (typeof record.code === "number") return record.code;
|
|
208
|
+
if (typeof record.status === "number") return record.status;
|
|
209
|
+
if (typeof record.data?.status === "number") return record.data.status;
|
|
210
|
+
}
|
|
211
|
+
function getErrorCause(error) {
|
|
212
|
+
if (!error || typeof error !== "object") return void 0;
|
|
213
|
+
return error.cause ?? error.data?.cause;
|
|
55
214
|
}
|
|
56
215
|
function isUnauthorized(error) {
|
|
57
|
-
if (
|
|
216
|
+
if (getErrorStatus(error) === 401) return true;
|
|
217
|
+
const cause = getErrorCause(error);
|
|
218
|
+
if (cause && cause !== error && isUnauthorized(cause)) return true;
|
|
58
219
|
const msg = toErrorMessage(error);
|
|
59
220
|
return msg.includes("Unauthorized") || msg.includes("401");
|
|
60
221
|
}
|
|
61
222
|
function isTransportNotImplemented(error) {
|
|
62
|
-
const
|
|
63
|
-
if (
|
|
223
|
+
const status = getErrorStatus(error);
|
|
224
|
+
if (status === 404 || status === 405) return true;
|
|
225
|
+
const cause = getErrorCause(error);
|
|
226
|
+
if (cause && cause !== error && isTransportNotImplemented(cause)) return true;
|
|
64
227
|
const msg = toErrorMessage(error);
|
|
65
|
-
return msg.includes("404") || msg.includes("405") || msg.includes("Not Implemented") || msg.includes("not implemented");
|
|
228
|
+
return msg.includes("404") || msg.includes("405") || msg.includes("Error POSTing to endpoint: Not Found") || msg.includes("Not Implemented") || msg.includes("not implemented");
|
|
66
229
|
}
|
|
67
230
|
//#endregion
|
|
68
231
|
//#region src/mcp/rpc.ts
|
|
@@ -107,9 +270,9 @@ var RPCClientTransport = class {
|
|
|
107
270
|
async send(message, options) {
|
|
108
271
|
if (!this._started || !this._stub) throw new Error("Transport not started");
|
|
109
272
|
try {
|
|
110
|
-
const result = await this._stub.handleMcpMessage(message);
|
|
111
|
-
if (!result) return;
|
|
112
|
-
const extra =
|
|
273
|
+
const result = await raceWithSignal(this._stub.handleMcpMessage(message), options?.requestSignal);
|
|
274
|
+
if (!result || options?.requestSignal?.aborted) return;
|
|
275
|
+
const extra = void 0;
|
|
113
276
|
const messages = Array.isArray(result) ? result : [result];
|
|
114
277
|
for (const msg of messages) this.onmessage?.(msg, extra);
|
|
115
278
|
} catch (error) {
|
|
@@ -282,7 +445,6 @@ var RPCServerTransport = class {
|
|
|
282
445
|
};
|
|
283
446
|
//#endregion
|
|
284
447
|
//#region src/mcp/client-connection.ts
|
|
285
|
-
const defaultClientOptions = { jsonSchemaValidator: new CfWorkerJsonSchemaValidator() };
|
|
286
448
|
/**
|
|
287
449
|
* Connection state machine for MCP client connections.
|
|
288
450
|
*
|
|
@@ -305,14 +467,6 @@ const MCPConnectionState = {
|
|
|
305
467
|
/** Connection failed at some point */
|
|
306
468
|
FAILED: "failed"
|
|
307
469
|
};
|
|
308
|
-
/** Derive the elicitation capability to advertise from the handler keys. */
|
|
309
|
-
function elicitationCapabilitiesFromHandlers(handlers) {
|
|
310
|
-
if (!handlers) return void 0;
|
|
311
|
-
const elicitation = {};
|
|
312
|
-
if (handlers.form) elicitation.form = {};
|
|
313
|
-
if (handlers.url) elicitation.url = {};
|
|
314
|
-
return elicitation.form || elicitation.url ? elicitation : void 0;
|
|
315
|
-
}
|
|
316
470
|
var MCPClientConnection = class {
|
|
317
471
|
constructor(url, _info, options = {
|
|
318
472
|
client: {},
|
|
@@ -330,29 +484,32 @@ var MCPClientConnection = class {
|
|
|
330
484
|
this._probingCapabilities = false;
|
|
331
485
|
this._onObservabilityEvent = new Emitter();
|
|
332
486
|
this.onObservabilityEvent = this._onObservabilityEvent.event;
|
|
487
|
+
this._onListChanged = new Emitter();
|
|
488
|
+
this.onListChanged = this._onListChanged.event;
|
|
333
489
|
this._elicitationEnabled = false;
|
|
334
490
|
this.options = {
|
|
335
491
|
...options,
|
|
336
|
-
client:
|
|
337
|
-
...defaultClientOptions,
|
|
338
|
-
...options.client
|
|
339
|
-
}
|
|
492
|
+
client: normalizeMcpClientOptions(options.client)
|
|
340
493
|
};
|
|
341
494
|
this.client = this.createClient();
|
|
342
495
|
}
|
|
343
496
|
createClient() {
|
|
344
|
-
const
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
497
|
+
const created = createMcpSdkClient(this._info, this.options.client, this.options.capabilitySeed, this.options.elicitationHandlers, {
|
|
498
|
+
tools: (error, tools) => {
|
|
499
|
+
if (!error && tools) this.tools = tools;
|
|
500
|
+
this._onListChanged.fire();
|
|
501
|
+
},
|
|
502
|
+
prompts: (error, prompts) => {
|
|
503
|
+
if (!error && prompts) this.prompts = prompts;
|
|
504
|
+
this._onListChanged.fire();
|
|
505
|
+
},
|
|
506
|
+
resources: (error, resources) => {
|
|
507
|
+
if (!error && resources) this.resources = resources;
|
|
508
|
+
this._onListChanged.fire();
|
|
353
509
|
}
|
|
354
|
-
};
|
|
355
|
-
|
|
510
|
+
});
|
|
511
|
+
this._elicitationEnabled = created.elicitationEnabled;
|
|
512
|
+
return created.client;
|
|
356
513
|
}
|
|
357
514
|
/**
|
|
358
515
|
* Configure the handler used for server-initiated elicitation requests.
|
|
@@ -367,7 +524,7 @@ var MCPClientConnection = class {
|
|
|
367
524
|
configureElicitationHandlers(handlers) {
|
|
368
525
|
this.options.elicitationHandlers = handlers;
|
|
369
526
|
this.options.capabilitySeed = void 0;
|
|
370
|
-
if (!this.
|
|
527
|
+
if (!this._transport) this.client = this.createClient();
|
|
371
528
|
}
|
|
372
529
|
/**
|
|
373
530
|
* Initialize a client connection, if authentication is required, the connection will be in the AUTHENTICATING state
|
|
@@ -378,7 +535,7 @@ var MCPClientConnection = class {
|
|
|
378
535
|
async init() {
|
|
379
536
|
const transportType = this.options.transport.type;
|
|
380
537
|
if (!transportType) throw new Error("Transport type must be specified");
|
|
381
|
-
if (this.
|
|
538
|
+
if (this._transport) {
|
|
382
539
|
this._transport = void 0;
|
|
383
540
|
try {
|
|
384
541
|
await this.client.close();
|
|
@@ -388,9 +545,7 @@ var MCPClientConnection = class {
|
|
|
388
545
|
const res = await this.tryConnect(transportType);
|
|
389
546
|
this.connectionState = res.state;
|
|
390
547
|
if (res.state === MCPConnectionState.CONNECTED && res.transport) {
|
|
391
|
-
if (this._elicitationEnabled) this.client.setRequestHandler(
|
|
392
|
-
return await this.handleElicitationRequest(request);
|
|
393
|
-
});
|
|
548
|
+
if (this._elicitationEnabled) this.client.setRequestHandler("elicitation/create", async (request, context) => await this.handleElicitationRequest(request, context.mcpReq.signal));
|
|
394
549
|
this.lastConnectedTransport = res.transport;
|
|
395
550
|
this._onObservabilityEvent.fire({
|
|
396
551
|
type: "mcp:client:connect",
|
|
@@ -422,19 +577,36 @@ var MCPClientConnection = class {
|
|
|
422
577
|
* - Explicit: finish on that transport
|
|
423
578
|
* - Auto: try streamable-http, then sse on 404/405/Not Implemented
|
|
424
579
|
*/
|
|
425
|
-
async finishAuthProbe(
|
|
580
|
+
async finishAuthProbe(callbackParams) {
|
|
426
581
|
if (!this.options.transport.authProvider) throw new Error("No auth provider configured");
|
|
427
582
|
const configuredType = this.options.transport.type;
|
|
428
583
|
if (!configuredType) throw new Error("Transport type must be specified");
|
|
429
584
|
const finishAuth = async (base) => {
|
|
430
585
|
const transport = this.getTransport(base);
|
|
431
|
-
|
|
586
|
+
let completed = false;
|
|
587
|
+
try {
|
|
588
|
+
if ("finishAuth" in transport && typeof transport.finishAuth === "function") {
|
|
589
|
+
await transport.finishAuth(callbackParams);
|
|
590
|
+
completed = true;
|
|
591
|
+
}
|
|
592
|
+
} finally {
|
|
593
|
+
if (typeof transport.close === "function") await transport.close().catch(() => {});
|
|
594
|
+
}
|
|
595
|
+
if (completed) this.client = this.createClient();
|
|
432
596
|
};
|
|
433
597
|
if (configuredType === "rpc") throw new Error("RPC transport does not support authentication");
|
|
434
598
|
const authTransport = this._pendingAuthTransport ?? this._transport;
|
|
435
599
|
this._pendingAuthTransport = void 0;
|
|
436
600
|
if (authTransport && "finishAuth" in authTransport && typeof authTransport.finishAuth === "function") {
|
|
437
|
-
|
|
601
|
+
let completed = false;
|
|
602
|
+
try {
|
|
603
|
+
await authTransport.finishAuth(callbackParams);
|
|
604
|
+
completed = true;
|
|
605
|
+
} finally {
|
|
606
|
+
if (typeof authTransport.close === "function") await authTransport.close().catch(() => {});
|
|
607
|
+
if (this._transport === authTransport) this._transport = void 0;
|
|
608
|
+
}
|
|
609
|
+
if (completed) this.client = this.createClient();
|
|
438
610
|
return;
|
|
439
611
|
}
|
|
440
612
|
if (configuredType === "sse" || configuredType === "streamable-http") {
|
|
@@ -454,12 +626,13 @@ var MCPClientConnection = class {
|
|
|
454
626
|
/**
|
|
455
627
|
* Complete OAuth authorization
|
|
456
628
|
*/
|
|
457
|
-
async completeAuthorization(
|
|
629
|
+
async completeAuthorization(callback, options = {}) {
|
|
458
630
|
const expectedState = options.alreadyAccepted ? MCPConnectionState.CONNECTING : MCPConnectionState.AUTHENTICATING;
|
|
459
631
|
if (this.connectionState !== expectedState) throw new Error(`Connection must be in ${expectedState} state to complete authorization`);
|
|
460
632
|
if (!options.alreadyAccepted) this.connectionState = MCPConnectionState.CONNECTING;
|
|
461
633
|
try {
|
|
462
|
-
|
|
634
|
+
const callbackParams = typeof callback === "string" ? new URLSearchParams({ code: callback }) : callback;
|
|
635
|
+
await this.finishAuthProbe(callbackParams);
|
|
463
636
|
} catch (error) {
|
|
464
637
|
this.connectionState = MCPConnectionState.FAILED;
|
|
465
638
|
throw error;
|
|
@@ -587,11 +760,11 @@ var MCPClientConnection = class {
|
|
|
587
760
|
return { success: true };
|
|
588
761
|
} catch (e) {
|
|
589
762
|
if (timeoutId !== void 0) clearTimeout(timeoutId);
|
|
590
|
-
this.connectionState = MCPConnectionState.CONNECTED;
|
|
763
|
+
this.connectionState = isUnauthorized(e) ? MCPConnectionState.AUTHENTICATING : MCPConnectionState.CONNECTED;
|
|
591
764
|
const error = e instanceof Error ? e.message : String(e);
|
|
592
765
|
return {
|
|
593
766
|
success: false,
|
|
594
|
-
reason: this._probingCapabilities && e instanceof
|
|
767
|
+
reason: this._probingCapabilities && e instanceof SdkHttpError && e.status === 404 ? "stale-session" : "error",
|
|
595
768
|
error
|
|
596
769
|
};
|
|
597
770
|
} finally {
|
|
@@ -613,8 +786,9 @@ var MCPClientConnection = class {
|
|
|
613
786
|
* Should only be called if serverCapabilities.tools exists
|
|
614
787
|
*/
|
|
615
788
|
async registerTools() {
|
|
616
|
-
if (this.
|
|
789
|
+
if (this._probingCapabilities) this.client.setNotificationHandler("notifications/tools/list_changed", async () => {
|
|
617
790
|
this.tools = await this.fetchTools();
|
|
791
|
+
this._onListChanged.fire();
|
|
618
792
|
});
|
|
619
793
|
return this.fetchTools();
|
|
620
794
|
}
|
|
@@ -623,8 +797,9 @@ var MCPClientConnection = class {
|
|
|
623
797
|
* Should only be called if serverCapabilities.resources exists
|
|
624
798
|
*/
|
|
625
799
|
async registerResources() {
|
|
626
|
-
if (this.
|
|
800
|
+
if (this._probingCapabilities) this.client.setNotificationHandler("notifications/resources/list_changed", async () => {
|
|
627
801
|
this.resources = await this.fetchResources();
|
|
802
|
+
this._onListChanged.fire();
|
|
628
803
|
});
|
|
629
804
|
return this.fetchResources();
|
|
630
805
|
}
|
|
@@ -633,49 +808,32 @@ var MCPClientConnection = class {
|
|
|
633
808
|
* Should only be called if serverCapabilities.prompts exists
|
|
634
809
|
*/
|
|
635
810
|
async registerPrompts() {
|
|
636
|
-
if (this.
|
|
811
|
+
if (this._probingCapabilities) this.client.setNotificationHandler("notifications/prompts/list_changed", async () => {
|
|
637
812
|
this.prompts = await this.fetchPrompts();
|
|
813
|
+
this._onListChanged.fire();
|
|
638
814
|
});
|
|
639
815
|
return this.fetchPrompts();
|
|
640
816
|
}
|
|
641
817
|
async registerResourceTemplates() {
|
|
642
818
|
return this.fetchResourceTemplates();
|
|
643
819
|
}
|
|
820
|
+
catalogFetchOptions() {
|
|
821
|
+
return {
|
|
822
|
+
probing: this._probingCapabilities,
|
|
823
|
+
onCapabilityError: this._capabilityErrorHandler.bind(this)
|
|
824
|
+
};
|
|
825
|
+
}
|
|
644
826
|
async fetchTools() {
|
|
645
|
-
|
|
646
|
-
let toolsResult = { tools: [] };
|
|
647
|
-
do {
|
|
648
|
-
toolsResult = await this.client.listTools({ cursor: toolsResult.nextCursor }).catch(this._capabilityErrorHandler({ tools: [] }, "tools/list"));
|
|
649
|
-
toolsAgg = toolsAgg.concat(toolsResult.tools);
|
|
650
|
-
} while (toolsResult.nextCursor);
|
|
651
|
-
return toolsAgg;
|
|
827
|
+
return fetchMcpTools(this.client, this.catalogFetchOptions());
|
|
652
828
|
}
|
|
653
829
|
async fetchResources() {
|
|
654
|
-
|
|
655
|
-
let resourcesResult = { resources: [] };
|
|
656
|
-
do {
|
|
657
|
-
resourcesResult = await this.client.listResources({ cursor: resourcesResult.nextCursor }).catch(this._capabilityErrorHandler({ resources: [] }, "resources/list"));
|
|
658
|
-
resourcesAgg = resourcesAgg.concat(resourcesResult.resources);
|
|
659
|
-
} while (resourcesResult.nextCursor);
|
|
660
|
-
return resourcesAgg;
|
|
830
|
+
return fetchMcpResources(this.client, this.catalogFetchOptions());
|
|
661
831
|
}
|
|
662
832
|
async fetchPrompts() {
|
|
663
|
-
|
|
664
|
-
let promptsResult = { prompts: [] };
|
|
665
|
-
do {
|
|
666
|
-
promptsResult = await this.client.listPrompts({ cursor: promptsResult.nextCursor }).catch(this._capabilityErrorHandler({ prompts: [] }, "prompts/list"));
|
|
667
|
-
promptsAgg = promptsAgg.concat(promptsResult.prompts);
|
|
668
|
-
} while (promptsResult.nextCursor);
|
|
669
|
-
return promptsAgg;
|
|
833
|
+
return fetchMcpPrompts(this.client, this.catalogFetchOptions());
|
|
670
834
|
}
|
|
671
835
|
async fetchResourceTemplates() {
|
|
672
|
-
|
|
673
|
-
let templatesResult = { resourceTemplates: [] };
|
|
674
|
-
do {
|
|
675
|
-
templatesResult = await this.client.listResourceTemplates({ cursor: templatesResult.nextCursor }).catch(this._capabilityErrorHandler({ resourceTemplates: [] }, "resources/templates/list"));
|
|
676
|
-
templatesAgg = templatesAgg.concat(templatesResult.resourceTemplates);
|
|
677
|
-
} while (templatesResult.nextCursor);
|
|
678
|
-
return templatesAgg;
|
|
836
|
+
return fetchMcpResourceTemplates(this.client, this.catalogFetchOptions());
|
|
679
837
|
}
|
|
680
838
|
/**
|
|
681
839
|
* Handle elicitation request from server.
|
|
@@ -685,10 +843,10 @@ var MCPClientConnection = class {
|
|
|
685
843
|
* @deprecated Overriding or instance-patching this method directly is
|
|
686
844
|
* deprecated — pass the `elicitationHandlers` connection option instead.
|
|
687
845
|
*/
|
|
688
|
-
async handleElicitationRequest(request) {
|
|
846
|
+
async handleElicitationRequest(request, signal) {
|
|
689
847
|
const mode = request.params.mode === "url" ? "url" : "form";
|
|
690
848
|
const handler = this.options.elicitationHandlers?.[mode];
|
|
691
|
-
if (handler) return handler(request);
|
|
849
|
+
if (handler) return raceWithSignal(signal ? handler(request, signal) : handler(request), signal);
|
|
692
850
|
if (this.options.elicitationHandlers) throw new Error(`No MCP ${mode}-mode elicitation handler configured for this connection.`);
|
|
693
851
|
throw new Error("Elicitation handler must be implemented for your platform. Provide the MCPClientConnection elicitationHandlers option, or register handlers through the MCP client manager before connecting.");
|
|
694
852
|
}
|
|
@@ -702,6 +860,26 @@ var MCPClientConnection = class {
|
|
|
702
860
|
clearResumedSession() {
|
|
703
861
|
if ("sessionId" in this.options.transport) delete this.options.transport.sessionId;
|
|
704
862
|
}
|
|
863
|
+
get protocolVersion() {
|
|
864
|
+
if (this._transport instanceof StreamableHTTPClientTransport) return this._transport.protocolVersion;
|
|
865
|
+
}
|
|
866
|
+
get discoverResult() {
|
|
867
|
+
return this.client.getDiscoverResult();
|
|
868
|
+
}
|
|
869
|
+
async openRestoredListSubscription() {
|
|
870
|
+
const capabilities = this.client.getServerCapabilities();
|
|
871
|
+
const filter = {
|
|
872
|
+
...capabilities?.tools?.listChanged && { toolsListChanged: true },
|
|
873
|
+
...capabilities?.prompts?.listChanged && { promptsListChanged: true },
|
|
874
|
+
...capabilities?.resources?.listChanged && { resourcesListChanged: true }
|
|
875
|
+
};
|
|
876
|
+
if (Object.keys(filter).length === 0) return;
|
|
877
|
+
try {
|
|
878
|
+
this._restoredListSubscription = await this.client.listen(filter);
|
|
879
|
+
} catch (error) {
|
|
880
|
+
this.client.onerror?.(error instanceof Error ? error : new Error(String(error)));
|
|
881
|
+
}
|
|
882
|
+
}
|
|
705
883
|
getTransportName(transport) {
|
|
706
884
|
if (transport instanceof StreamableHTTPClientTransport) return "streamable-http";
|
|
707
885
|
if (transport instanceof SSEClientTransport) return "sse";
|
|
@@ -711,6 +889,8 @@ var MCPClientConnection = class {
|
|
|
711
889
|
async close() {
|
|
712
890
|
const transport = this._transport;
|
|
713
891
|
this._transport = void 0;
|
|
892
|
+
await this._restoredListSubscription?.close().catch(() => {});
|
|
893
|
+
this._restoredListSubscription = void 0;
|
|
714
894
|
const url = this.url.toString();
|
|
715
895
|
const transportName = this.getTransportName(transport);
|
|
716
896
|
if (transport instanceof StreamableHTTPClientTransport && transport.sessionId) try {
|
|
@@ -774,9 +954,14 @@ var MCPClientConnection = class {
|
|
|
774
954
|
const hasFallback = transportType === "auto" && currentTransportType === "streamable-http" && !isLastTransport;
|
|
775
955
|
const transport = this.getTransport(currentTransportType);
|
|
776
956
|
try {
|
|
777
|
-
|
|
957
|
+
const prior = transport instanceof StreamableHTTPClientTransport && transport.sessionId && this.options.discoverResult ? {
|
|
958
|
+
kind: "modern",
|
|
959
|
+
discover: this.options.discoverResult
|
|
960
|
+
} : void 0;
|
|
961
|
+
await this.client.connect(transport, prior ? { prior } : void 0);
|
|
778
962
|
this._transport = transport;
|
|
779
963
|
this._pendingAuthTransport = void 0;
|
|
964
|
+
if (prior) await this.openRestoredListSubscription();
|
|
780
965
|
return {
|
|
781
966
|
state: MCPConnectionState.CONNECTED,
|
|
782
967
|
transport: currentTransportType
|
|
@@ -819,6 +1004,87 @@ var MCPClientConnection = class {
|
|
|
819
1004
|
}
|
|
820
1005
|
};
|
|
821
1006
|
//#endregion
|
|
1007
|
+
//#region src/mcp/client-storage.ts
|
|
1008
|
+
function persistClientOptions(client) {
|
|
1009
|
+
if (!client) return void 0;
|
|
1010
|
+
return {
|
|
1011
|
+
capabilities: client.capabilities,
|
|
1012
|
+
supportedProtocolVersions: client.supportedProtocolVersions,
|
|
1013
|
+
enforceStrictCapabilities: client.enforceStrictCapabilities,
|
|
1014
|
+
debouncedNotificationMethods: client.debouncedNotificationMethods,
|
|
1015
|
+
versionNegotiation: client.versionNegotiation,
|
|
1016
|
+
inputRequired: client.inputRequired,
|
|
1017
|
+
listMaxPages: client.listMaxPages,
|
|
1018
|
+
cachePartition: client.cachePartition,
|
|
1019
|
+
defaultCacheTtlMs: client.defaultCacheTtlMs
|
|
1020
|
+
};
|
|
1021
|
+
}
|
|
1022
|
+
function persistTransportOptions(value) {
|
|
1023
|
+
if (!value) return void 0;
|
|
1024
|
+
return {
|
|
1025
|
+
type: value.type,
|
|
1026
|
+
headers: value.headers,
|
|
1027
|
+
requestInit: value.requestInit,
|
|
1028
|
+
reconnectionOptions: value.reconnectionOptions,
|
|
1029
|
+
skipIssuerMetadataValidation: value.skipIssuerMetadataValidation,
|
|
1030
|
+
onInsufficientScope: value.onInsufficientScope,
|
|
1031
|
+
maxStepUpRetries: value.maxStepUpRetries,
|
|
1032
|
+
sessionId: value.sessionId,
|
|
1033
|
+
protocolVersion: value.protocolVersion
|
|
1034
|
+
};
|
|
1035
|
+
}
|
|
1036
|
+
function encodeMcpServerOptions(options) {
|
|
1037
|
+
return JSON.stringify({
|
|
1038
|
+
client: persistClientOptions(options.client),
|
|
1039
|
+
transport: persistTransportOptions(options.transport),
|
|
1040
|
+
discoverResult: options.discoverResult,
|
|
1041
|
+
retry: options.retry,
|
|
1042
|
+
bindingName: options.bindingName,
|
|
1043
|
+
props: options.props,
|
|
1044
|
+
capabilities: options.capabilities
|
|
1045
|
+
});
|
|
1046
|
+
}
|
|
1047
|
+
function decodeMcpServerOptions(value) {
|
|
1048
|
+
if (!value) return {};
|
|
1049
|
+
const parsed = JSON.parse(value);
|
|
1050
|
+
const transport = persistTransportOptions(parsed.transport);
|
|
1051
|
+
const statelessWithoutPrior = transport?.protocolVersion === "2026-07-28" && !parsed.discoverResult;
|
|
1052
|
+
if (transport?.sessionId && (!transport.protocolVersion || statelessWithoutPrior)) {
|
|
1053
|
+
delete transport.sessionId;
|
|
1054
|
+
delete transport.protocolVersion;
|
|
1055
|
+
delete parsed.discoverResult;
|
|
1056
|
+
}
|
|
1057
|
+
return {
|
|
1058
|
+
client: persistClientOptions(parsed.client),
|
|
1059
|
+
transport,
|
|
1060
|
+
discoverResult: parsed.discoverResult,
|
|
1061
|
+
retry: parsed.retry,
|
|
1062
|
+
...parsed.bindingName !== void 0 && { bindingName: parsed.bindingName },
|
|
1063
|
+
...parsed.props !== void 0 && { props: parsed.props },
|
|
1064
|
+
capabilities: parsed.capabilities
|
|
1065
|
+
};
|
|
1066
|
+
}
|
|
1067
|
+
function withMcpSession(options, session) {
|
|
1068
|
+
const transport = { ...options.transport ?? {} };
|
|
1069
|
+
if (!session) {
|
|
1070
|
+
delete transport.sessionId;
|
|
1071
|
+
delete transport.protocolVersion;
|
|
1072
|
+
const next = {
|
|
1073
|
+
...options,
|
|
1074
|
+
transport
|
|
1075
|
+
};
|
|
1076
|
+
delete next.discoverResult;
|
|
1077
|
+
return next;
|
|
1078
|
+
}
|
|
1079
|
+
transport.sessionId = session.id;
|
|
1080
|
+
transport.protocolVersion = session.protocolVersion;
|
|
1081
|
+
return {
|
|
1082
|
+
...options,
|
|
1083
|
+
transport,
|
|
1084
|
+
...session.discoverResult ? { discoverResult: session.discoverResult } : { discoverResult: void 0 }
|
|
1085
|
+
};
|
|
1086
|
+
}
|
|
1087
|
+
//#endregion
|
|
822
1088
|
//#region src/mcp/client.ts
|
|
823
1089
|
/** Maximum length of a normalized MCP server id. */
|
|
824
1090
|
const MCP_SERVER_ID_MAX_LENGTH = 64;
|
|
@@ -986,8 +1252,8 @@ var MCPClientManager = class {
|
|
|
986
1252
|
const form = handlers.form;
|
|
987
1253
|
const url = handlers.url;
|
|
988
1254
|
return {
|
|
989
|
-
form: form ? (request) => form(request, serverId) : void 0,
|
|
990
|
-
url: url ? (request) => url(request, serverId) : void 0
|
|
1255
|
+
form: form ? (request, signal) => signal ? form(request, serverId, signal) : form(request, serverId) : void 0,
|
|
1256
|
+
url: url ? (request, signal) => signal ? url(request, serverId, signal) : url(request, serverId) : void 0
|
|
991
1257
|
};
|
|
992
1258
|
}
|
|
993
1259
|
sql(query, ...bindings) {
|
|
@@ -1097,7 +1363,7 @@ var MCPClientManager = class {
|
|
|
1097
1363
|
getStoredServerOptions(serverId) {
|
|
1098
1364
|
const rows = this.sql("SELECT server_options FROM cf_agents_mcp_servers WHERE id = ?", serverId);
|
|
1099
1365
|
if (!rows.length || !rows[0].server_options) return void 0;
|
|
1100
|
-
return
|
|
1366
|
+
return decodeMcpServerOptions(rows[0].server_options);
|
|
1101
1367
|
}
|
|
1102
1368
|
/**
|
|
1103
1369
|
* Clear the capabilities persisted on a stored server row. Called once a
|
|
@@ -1110,12 +1376,12 @@ var MCPClientManager = class {
|
|
|
1110
1376
|
clearStoredCapabilities(serverId) {
|
|
1111
1377
|
const row = this.sql("SELECT id, name, server_url, client_id, auth_url, callback_url, server_options FROM cf_agents_mcp_servers WHERE id = ?", serverId)[0];
|
|
1112
1378
|
if (!row?.server_options) return;
|
|
1113
|
-
const options =
|
|
1379
|
+
const options = decodeMcpServerOptions(row.server_options);
|
|
1114
1380
|
if (!options.capabilities) return;
|
|
1115
1381
|
options.capabilities = void 0;
|
|
1116
1382
|
this.saveServerToStorage({
|
|
1117
1383
|
...row,
|
|
1118
|
-
server_options:
|
|
1384
|
+
server_options: encodeMcpServerOptions(options)
|
|
1119
1385
|
});
|
|
1120
1386
|
}
|
|
1121
1387
|
/**
|
|
@@ -1127,22 +1393,18 @@ var MCPClientManager = class {
|
|
|
1127
1393
|
clearServerAuthUrl(serverId) {
|
|
1128
1394
|
this.sql("UPDATE cf_agents_mcp_servers SET auth_url = NULL WHERE id = ?", serverId);
|
|
1129
1395
|
}
|
|
1130
|
-
|
|
1396
|
+
updateStoredSession(id, sessionId, protocolVersion, discoverResult) {
|
|
1131
1397
|
const serverRow = this.getServersFromStorage().find((server) => server.id === id);
|
|
1132
1398
|
if (!serverRow) return;
|
|
1133
|
-
const
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
};
|
|
1139
|
-
if (!sessionId) delete nextTransport.sessionId;
|
|
1399
|
+
const options = decodeMcpServerOptions(serverRow.server_options);
|
|
1400
|
+
const next = sessionId && protocolVersion ? withMcpSession(options, {
|
|
1401
|
+
id: sessionId,
|
|
1402
|
+
protocolVersion,
|
|
1403
|
+
discoverResult
|
|
1404
|
+
}) : withMcpSession(options);
|
|
1140
1405
|
this.saveServerToStorage({
|
|
1141
1406
|
...serverRow,
|
|
1142
|
-
server_options:
|
|
1143
|
-
...parsedOptions,
|
|
1144
|
-
transport: nextTransport
|
|
1145
|
-
})
|
|
1407
|
+
server_options: encodeMcpServerOptions(next)
|
|
1146
1408
|
});
|
|
1147
1409
|
}
|
|
1148
1410
|
failConnection(serverId, error) {
|
|
@@ -1201,12 +1463,12 @@ var MCPClientManager = class {
|
|
|
1201
1463
|
console.warn(`[MCPClientManager] Failed to clean up stale OAuth callback state for server "${serverId}":`, cleanupError);
|
|
1202
1464
|
}
|
|
1203
1465
|
}
|
|
1204
|
-
async completeAuthorizationAndCleanupVerifier(serverId, conn, authProvider, state,
|
|
1466
|
+
async completeAuthorizationAndCleanupVerifier(serverId, conn, authProvider, state, callbackParams) {
|
|
1205
1467
|
await this.runWithCodeVerifierState(authProvider, state, async () => {
|
|
1206
1468
|
let completeError;
|
|
1207
1469
|
let cleanupError;
|
|
1208
1470
|
try {
|
|
1209
|
-
await conn.completeAuthorization(
|
|
1471
|
+
await conn.completeAuthorization(callbackParams, { alreadyAccepted: true });
|
|
1210
1472
|
} catch (error) {
|
|
1211
1473
|
completeError = error;
|
|
1212
1474
|
}
|
|
@@ -1253,7 +1515,7 @@ var MCPClientManager = class {
|
|
|
1253
1515
|
client_id: null,
|
|
1254
1516
|
auth_url: null,
|
|
1255
1517
|
callback_url: "",
|
|
1256
|
-
server_options:
|
|
1518
|
+
server_options: encodeMcpServerOptions({
|
|
1257
1519
|
bindingName,
|
|
1258
1520
|
props,
|
|
1259
1521
|
capabilities: this.advertisedHandlerCapabilities()
|
|
@@ -1292,8 +1554,7 @@ var MCPClientManager = class {
|
|
|
1292
1554
|
this.cleanupClosedConnection(server.id);
|
|
1293
1555
|
}
|
|
1294
1556
|
}
|
|
1295
|
-
const parsedOptions =
|
|
1296
|
-
if (parsedOptions?.client) delete parsedOptions.client.jsonSchemaValidator;
|
|
1557
|
+
const parsedOptions = decodeMcpServerOptions(server.server_options);
|
|
1297
1558
|
let authProvider;
|
|
1298
1559
|
if (server.callback_url) {
|
|
1299
1560
|
authProvider = this._createAuthProviderFn ? this._createAuthProviderFn(server.callback_url) : this.createAuthProvider(server.id, server.callback_url, clientName, server.client_id ?? void 0);
|
|
@@ -1306,7 +1567,8 @@ var MCPClientManager = class {
|
|
|
1306
1567
|
...parsedOptions?.transport ?? {},
|
|
1307
1568
|
type: parsedOptions?.transport?.type ?? "auto",
|
|
1308
1569
|
authProvider
|
|
1309
|
-
}
|
|
1570
|
+
},
|
|
1571
|
+
discoverResult: parsedOptions?.discoverResult
|
|
1310
1572
|
});
|
|
1311
1573
|
if (server.auth_url) {
|
|
1312
1574
|
conn.connectionState = MCPConnectionState.AUTHENTICATING;
|
|
@@ -1403,7 +1665,7 @@ var MCPClientManager = class {
|
|
|
1403
1665
|
if (replaced) {
|
|
1404
1666
|
delete this.mcpConnections[id];
|
|
1405
1667
|
await replaced.close().catch(() => {});
|
|
1406
|
-
this.
|
|
1668
|
+
this.updateStoredSession(id, void 0);
|
|
1407
1669
|
}
|
|
1408
1670
|
this.createConnection(id, url, {
|
|
1409
1671
|
client: options.client,
|
|
@@ -1468,7 +1730,8 @@ var MCPClientManager = class {
|
|
|
1468
1730
|
client: options.client ?? {},
|
|
1469
1731
|
transport: normalizedTransport,
|
|
1470
1732
|
elicitationHandlers: this.scopedElicitationHandlers(id),
|
|
1471
|
-
capabilitySeed
|
|
1733
|
+
capabilitySeed,
|
|
1734
|
+
discoverResult: options.discoverResult
|
|
1472
1735
|
});
|
|
1473
1736
|
const store = new DisposableStore();
|
|
1474
1737
|
const existing = this._connectionDisposables.get(id);
|
|
@@ -1477,6 +1740,9 @@ var MCPClientManager = class {
|
|
|
1477
1740
|
store.add(this.mcpConnections[id].onObservabilityEvent((event) => {
|
|
1478
1741
|
this._onObservabilityEvent.fire(event);
|
|
1479
1742
|
}));
|
|
1743
|
+
store.add(this.mcpConnections[id].onListChanged(() => {
|
|
1744
|
+
this._onServerStateChanged.fire();
|
|
1745
|
+
}));
|
|
1480
1746
|
if (capabilitySeed) {
|
|
1481
1747
|
const conn = this.mcpConnections[id];
|
|
1482
1748
|
const seedClear = conn.onObservabilityEvent((event) => {
|
|
@@ -1507,8 +1773,6 @@ var MCPClientManager = class {
|
|
|
1507
1773
|
type: options.transport?.type ?? "auto"
|
|
1508
1774
|
}
|
|
1509
1775
|
});
|
|
1510
|
-
const { authProvider: _, ...transportWithoutAuth } = options.transport ?? {};
|
|
1511
|
-
const { jsonSchemaValidator: _validator, ...serializableClient } = options.client ?? {};
|
|
1512
1776
|
this.saveServerToStorage({
|
|
1513
1777
|
id,
|
|
1514
1778
|
name: options.name,
|
|
@@ -1516,9 +1780,9 @@ var MCPClientManager = class {
|
|
|
1516
1780
|
callback_url: options.callbackUrl ?? "",
|
|
1517
1781
|
client_id: options.clientId ?? null,
|
|
1518
1782
|
auth_url: options.authUrl ?? null,
|
|
1519
|
-
server_options:
|
|
1520
|
-
client:
|
|
1521
|
-
transport:
|
|
1783
|
+
server_options: encodeMcpServerOptions({
|
|
1784
|
+
client: options.client,
|
|
1785
|
+
transport: options.transport,
|
|
1522
1786
|
retry: options.retry,
|
|
1523
1787
|
capabilities: this.advertisedHandlerCapabilities()
|
|
1524
1788
|
})
|
|
@@ -1526,6 +1790,32 @@ var MCPClientManager = class {
|
|
|
1526
1790
|
this._onServerStateChanged.fire();
|
|
1527
1791
|
return id;
|
|
1528
1792
|
}
|
|
1793
|
+
/** Persist and emit an OAuth continuation produced by connect or discovery. */
|
|
1794
|
+
persistAuthContinuation(id, conn) {
|
|
1795
|
+
const authProvider = conn.options.transport.authProvider;
|
|
1796
|
+
const authUrl = authProvider?.authUrl;
|
|
1797
|
+
if (!authUrl || !authProvider.redirectUrl) return void 0;
|
|
1798
|
+
const clientId = authProvider.clientId;
|
|
1799
|
+
const serverRow = this.getServersFromStorage().find((s) => s.id === id);
|
|
1800
|
+
if (serverRow) this.saveServerToStorage({
|
|
1801
|
+
...serverRow,
|
|
1802
|
+
auth_url: authUrl,
|
|
1803
|
+
client_id: clientId ?? null
|
|
1804
|
+
});
|
|
1805
|
+
this._onObservabilityEvent.fire({
|
|
1806
|
+
type: "mcp:client:authorize",
|
|
1807
|
+
payload: {
|
|
1808
|
+
serverId: id,
|
|
1809
|
+
authUrl,
|
|
1810
|
+
clientId
|
|
1811
|
+
},
|
|
1812
|
+
timestamp: Date.now()
|
|
1813
|
+
});
|
|
1814
|
+
return {
|
|
1815
|
+
authUrl,
|
|
1816
|
+
clientId
|
|
1817
|
+
};
|
|
1818
|
+
}
|
|
1529
1819
|
/**
|
|
1530
1820
|
* Connect to an already registered MCP server and initialize the connection.
|
|
1531
1821
|
*
|
|
@@ -1544,7 +1834,7 @@ var MCPClientManager = class {
|
|
|
1544
1834
|
const conn = this.mcpConnections[id];
|
|
1545
1835
|
if (!conn) throw new Error(`Server ${id} is not registered. Call registerServer() first.`);
|
|
1546
1836
|
const error = await conn.init();
|
|
1547
|
-
this.
|
|
1837
|
+
this.updateStoredSession(id, conn.sessionId, conn.protocolVersion, conn.discoverResult);
|
|
1548
1838
|
this._onServerStateChanged.fire();
|
|
1549
1839
|
switch (conn.connectionState) {
|
|
1550
1840
|
case MCPConnectionState.FAILED: return {
|
|
@@ -1552,35 +1842,18 @@ var MCPClientManager = class {
|
|
|
1552
1842
|
error: error ?? "Unknown connection error"
|
|
1553
1843
|
};
|
|
1554
1844
|
case MCPConnectionState.AUTHENTICATING: {
|
|
1555
|
-
const
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
const serverRow = this.getServersFromStorage().find((s) => s.id === id);
|
|
1563
|
-
if (serverRow) {
|
|
1564
|
-
this.saveServerToStorage({
|
|
1565
|
-
...serverRow,
|
|
1566
|
-
auth_url: authUrl,
|
|
1567
|
-
client_id: clientId ?? null
|
|
1568
|
-
});
|
|
1569
|
-
this._onServerStateChanged.fire();
|
|
1845
|
+
const auth = this.persistAuthContinuation(id, conn);
|
|
1846
|
+
if (!auth) {
|
|
1847
|
+
const provider = conn.options.transport.authProvider;
|
|
1848
|
+
return {
|
|
1849
|
+
state: MCPConnectionState.FAILED,
|
|
1850
|
+
error: `OAuth configuration incomplete: missing ${!provider?.authUrl ? "authUrl" : "redirectUrl"}`
|
|
1851
|
+
};
|
|
1570
1852
|
}
|
|
1571
|
-
this.
|
|
1572
|
-
type: "mcp:client:authorize",
|
|
1573
|
-
payload: {
|
|
1574
|
-
serverId: id,
|
|
1575
|
-
authUrl,
|
|
1576
|
-
clientId
|
|
1577
|
-
},
|
|
1578
|
-
timestamp: Date.now()
|
|
1579
|
-
});
|
|
1853
|
+
this._onServerStateChanged.fire();
|
|
1580
1854
|
return {
|
|
1581
1855
|
state: conn.connectionState,
|
|
1582
|
-
|
|
1583
|
-
clientId
|
|
1856
|
+
...auth
|
|
1584
1857
|
};
|
|
1585
1858
|
}
|
|
1586
1859
|
case MCPConnectionState.CONNECTED: return { state: conn.connectionState };
|
|
@@ -1616,7 +1889,6 @@ var MCPClientManager = class {
|
|
|
1616
1889
|
const code = url.searchParams.get("code");
|
|
1617
1890
|
const state = url.searchParams.get("state");
|
|
1618
1891
|
const error = url.searchParams.get("error");
|
|
1619
|
-
const errorDescription = url.searchParams.get("error_description");
|
|
1620
1892
|
if (!state) return {
|
|
1621
1893
|
valid: false,
|
|
1622
1894
|
error: "Unauthorized: no state provided"
|
|
@@ -1626,13 +1898,7 @@ var MCPClientManager = class {
|
|
|
1626
1898
|
valid: false,
|
|
1627
1899
|
error: "No serverId found in state parameter. Expected format: {nonce}.{serverId}"
|
|
1628
1900
|
};
|
|
1629
|
-
if (error) return {
|
|
1630
|
-
serverId,
|
|
1631
|
-
state,
|
|
1632
|
-
valid: false,
|
|
1633
|
-
error: errorDescription || error
|
|
1634
|
-
};
|
|
1635
|
-
if (!code) return {
|
|
1901
|
+
if (!code && !error) return {
|
|
1636
1902
|
serverId,
|
|
1637
1903
|
state,
|
|
1638
1904
|
valid: false,
|
|
@@ -1651,8 +1917,8 @@ var MCPClientManager = class {
|
|
|
1651
1917
|
return {
|
|
1652
1918
|
valid: true,
|
|
1653
1919
|
serverId,
|
|
1654
|
-
|
|
1655
|
-
|
|
1920
|
+
state,
|
|
1921
|
+
callbackParams: url.searchParams
|
|
1656
1922
|
};
|
|
1657
1923
|
}
|
|
1658
1924
|
async handleCallbackRequest(req) {
|
|
@@ -1678,7 +1944,7 @@ var MCPClientManager = class {
|
|
|
1678
1944
|
authError: validation.error
|
|
1679
1945
|
};
|
|
1680
1946
|
}
|
|
1681
|
-
const { serverId,
|
|
1947
|
+
const { serverId, state, callbackParams } = validation;
|
|
1682
1948
|
const conn = this.mcpConnections[serverId];
|
|
1683
1949
|
try {
|
|
1684
1950
|
if (!conn.options.transport.authProvider) throw new Error("Trying to finalize authentication for a server connection without an authProvider");
|
|
@@ -1690,7 +1956,7 @@ var MCPClientManager = class {
|
|
|
1690
1956
|
await this.consumeStaleOAuthState(serverId, authProvider, state);
|
|
1691
1957
|
return this.oauthCallbackSuccess(serverId, conn);
|
|
1692
1958
|
}
|
|
1693
|
-
return this.ignoreUnverifiedCallback(serverId, stateValidation.error
|
|
1959
|
+
return this.ignoreUnverifiedCallback(serverId, callbackParams.get("error_description") ?? callbackParams.get("error") ?? stateValidation.error ?? "Invalid state");
|
|
1694
1960
|
}
|
|
1695
1961
|
if (this.isAuthAcceptedConnection(conn)) {
|
|
1696
1962
|
await this.consumeStaleOAuthState(serverId, authProvider, state);
|
|
@@ -1699,8 +1965,8 @@ var MCPClientManager = class {
|
|
|
1699
1965
|
if (conn.connectionState !== MCPConnectionState.AUTHENTICATING && conn.connectionState !== MCPConnectionState.FAILED) throw new Error(`Failed to authenticate from "${conn.connectionState}" state`);
|
|
1700
1966
|
conn.connectionState = MCPConnectionState.CONNECTING;
|
|
1701
1967
|
await authProvider.consumeState(state);
|
|
1702
|
-
await this.completeAuthorizationAndCleanupVerifier(serverId, conn, authProvider, state,
|
|
1703
|
-
this.
|
|
1968
|
+
await this.completeAuthorizationAndCleanupVerifier(serverId, conn, authProvider, state, callbackParams);
|
|
1969
|
+
this.updateStoredSession(serverId, conn.sessionId, conn.protocolVersion, conn.discoverResult);
|
|
1704
1970
|
const result = this.oauthCallbackSuccess(serverId, conn);
|
|
1705
1971
|
this._onServerStateChanged.fire();
|
|
1706
1972
|
return result;
|
|
@@ -1734,6 +2000,7 @@ var MCPClientManager = class {
|
|
|
1734
2000
|
}
|
|
1735
2001
|
const result = await conn.discover(options);
|
|
1736
2002
|
if (!result.success && result.reason === "stale-session") return this._recoverStaleSession(conn, serverId, options);
|
|
2003
|
+
if (conn.connectionState === MCPConnectionState.AUTHENTICATING) this.persistAuthContinuation(serverId, conn);
|
|
1737
2004
|
this._onServerStateChanged.fire();
|
|
1738
2005
|
return this._toDiscoverResult(conn, result);
|
|
1739
2006
|
}
|
|
@@ -1749,7 +2016,7 @@ var MCPClientManager = class {
|
|
|
1749
2016
|
}
|
|
1750
2017
|
async _recoverStaleSession(conn, serverId, options) {
|
|
1751
2018
|
conn.clearResumedSession();
|
|
1752
|
-
this.
|
|
2019
|
+
this.updateStoredSession(serverId, void 0);
|
|
1753
2020
|
let connectResult;
|
|
1754
2021
|
try {
|
|
1755
2022
|
connectResult = await this.connectToServer(serverId);
|
|
@@ -1860,12 +2127,12 @@ var MCPClientManager = class {
|
|
|
1860
2127
|
persistAdvertisedCapabilities() {
|
|
1861
2128
|
const capabilities = this.advertisedHandlerCapabilities();
|
|
1862
2129
|
for (const server of this.getServersFromStorage()) {
|
|
1863
|
-
const options =
|
|
2130
|
+
const options = decodeMcpServerOptions(server.server_options);
|
|
1864
2131
|
if (JSON.stringify(options.capabilities) === JSON.stringify(capabilities)) continue;
|
|
1865
2132
|
options.capabilities = capabilities;
|
|
1866
2133
|
this.saveServerToStorage({
|
|
1867
2134
|
...server,
|
|
1868
|
-
server_options:
|
|
2135
|
+
server_options: encodeMcpServerOptions(options)
|
|
1869
2136
|
});
|
|
1870
2137
|
}
|
|
1871
2138
|
}
|
|
@@ -1991,7 +2258,7 @@ var MCPClientManager = class {
|
|
|
1991
2258
|
* (closes connection AND removes from storage).
|
|
1992
2259
|
*/
|
|
1993
2260
|
cleanupClosedConnection(id) {
|
|
1994
|
-
this.
|
|
2261
|
+
this.updateStoredSession(id, void 0);
|
|
1995
2262
|
const store = this._connectionDisposables.get(id);
|
|
1996
2263
|
if (store) store.dispose();
|
|
1997
2264
|
this._connectionDisposables.delete(id);
|
|
@@ -2074,28 +2341,27 @@ var MCPClientManager = class {
|
|
|
2074
2341
|
listResourceTemplates(filter) {
|
|
2075
2342
|
return getNamespacedData(this.filterConnections(filter), "resourceTemplates");
|
|
2076
2343
|
}
|
|
2077
|
-
|
|
2078
|
-
* Namespaced version of callTool
|
|
2079
|
-
*/
|
|
2080
|
-
async callTool(params, resultSchema, options) {
|
|
2344
|
+
async callTool(params, schemaOrOptions, options) {
|
|
2081
2345
|
const { serverId, ...mcpParams } = params;
|
|
2082
2346
|
const unqualifiedName = mcpParams.name.replace(`${serverId}.`, "");
|
|
2083
|
-
return this.mcpConnections[serverId].client
|
|
2347
|
+
return callV2Tool(this.mcpConnections[serverId].client, {
|
|
2084
2348
|
...mcpParams,
|
|
2085
2349
|
name: unqualifiedName
|
|
2086
|
-
},
|
|
2350
|
+
}, schemaOrOptions, options);
|
|
2087
2351
|
}
|
|
2088
2352
|
/**
|
|
2089
2353
|
* Namespaced version of readResource
|
|
2090
2354
|
*/
|
|
2091
2355
|
readResource(params, options) {
|
|
2092
|
-
|
|
2356
|
+
const { serverId, ...mcpParams } = params;
|
|
2357
|
+
return this.mcpConnections[serverId].client.readResource(mcpParams, options);
|
|
2093
2358
|
}
|
|
2094
2359
|
/**
|
|
2095
2360
|
* Namespaced version of getPrompt
|
|
2096
2361
|
*/
|
|
2097
2362
|
getPrompt(params, options) {
|
|
2098
|
-
|
|
2363
|
+
const { serverId, ...mcpParams } = params;
|
|
2364
|
+
return this.mcpConnections[serverId].client.getPrompt(mcpParams, options);
|
|
2099
2365
|
}
|
|
2100
2366
|
};
|
|
2101
2367
|
function getNamespacedData(mcpClients, type) {
|
|
@@ -2116,4 +2382,4 @@ function getNamespacedData(mcpClients, type) {
|
|
|
2116
2382
|
//#endregion
|
|
2117
2383
|
export { MCPConnectionState as a, RPC_DO_PREFIX as c, normalizeServerId as i, DisposableStore as l, MCP_SERVER_ID_MAX_LENGTH as n, RPCClientTransport as o, getNamespacedData as r, RPCServerTransport as s, MCPClientManager as t };
|
|
2118
2384
|
|
|
2119
|
-
//# sourceMappingURL=client-
|
|
2385
|
+
//# sourceMappingURL=client-zqKcsyFa.js.map
|