@mcp-use/client 2.1.0 → 2.1.1-canary.1
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/.tsbuildinfo +1 -1
- package/dist/auth/browser.d.ts +8 -0
- package/dist/auth/browser.d.ts.map +1 -1
- package/dist/auth/flow.d.ts +9 -0
- package/dist/auth/flow.d.ts.map +1 -1
- package/dist/core/browser.d.ts.map +1 -1
- package/dist/core/config.d.ts +6 -0
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/session.d.ts +19 -0
- package/dist/core/session.d.ts.map +1 -1
- package/dist/index-browser.d.ts +1 -1
- package/dist/index-browser.d.ts.map +1 -1
- package/dist/index-browser.js +286 -41
- package/dist/index-browser.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +651 -407
- package/dist/index.js.map +1 -1
- package/dist/react/McpClientProvider.d.ts.map +1 -1
- package/dist/react/index.d.ts +1 -0
- package/dist/react/index.d.ts.map +1 -1
- package/dist/react/index.js +488 -179
- package/dist/react/index.js.map +1 -1
- package/dist/react/types.d.ts +10 -1
- package/dist/react/types.d.ts.map +1 -1
- package/dist/react/useMcp-operations.d.ts +1 -0
- package/dist/react/useMcp-operations.d.ts.map +1 -1
- package/dist/react/useMcp.d.ts.map +1 -1
- package/dist/transport/base.d.ts +16 -1
- package/dist/transport/base.d.ts.map +1 -1
- package/dist/transport/http.d.ts +14 -0
- package/dist/transport/http.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -142,6 +142,268 @@ var init_logging = __esm({
|
|
|
142
142
|
}
|
|
143
143
|
});
|
|
144
144
|
|
|
145
|
+
// src/auth/popup.ts
|
|
146
|
+
function hasStoredTokens(tokensKey) {
|
|
147
|
+
try {
|
|
148
|
+
return typeof localStorage !== "undefined" && !!localStorage.getItem(tokensKey);
|
|
149
|
+
} catch {
|
|
150
|
+
return false;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
function runAuthPopup({
|
|
154
|
+
popup,
|
|
155
|
+
state,
|
|
156
|
+
tokensKey,
|
|
157
|
+
timeoutMs = 5 * 6e4,
|
|
158
|
+
closePollMs = 1e3,
|
|
159
|
+
closeGraceMs = 2e4,
|
|
160
|
+
expectedOrigin = typeof window !== "undefined" ? window.location.origin : ""
|
|
161
|
+
}) {
|
|
162
|
+
return new Promise((resolve) => {
|
|
163
|
+
let settled = false;
|
|
164
|
+
let closeTimer = null;
|
|
165
|
+
let timeoutTimer = null;
|
|
166
|
+
let graceTimer = null;
|
|
167
|
+
let broadcastChannel = null;
|
|
168
|
+
const cleanup = () => {
|
|
169
|
+
if (closeTimer) {
|
|
170
|
+
clearInterval(closeTimer);
|
|
171
|
+
closeTimer = null;
|
|
172
|
+
}
|
|
173
|
+
if (timeoutTimer) {
|
|
174
|
+
clearTimeout(timeoutTimer);
|
|
175
|
+
timeoutTimer = null;
|
|
176
|
+
}
|
|
177
|
+
if (graceTimer) {
|
|
178
|
+
clearTimeout(graceTimer);
|
|
179
|
+
graceTimer = null;
|
|
180
|
+
}
|
|
181
|
+
if (typeof window !== "undefined") {
|
|
182
|
+
window.removeEventListener("message", messageHandler);
|
|
183
|
+
window.removeEventListener("storage", storageHandler);
|
|
184
|
+
}
|
|
185
|
+
if (broadcastChannel) {
|
|
186
|
+
try {
|
|
187
|
+
broadcastChannel.removeEventListener("message", broadcastHandler);
|
|
188
|
+
broadcastChannel.close();
|
|
189
|
+
} catch {
|
|
190
|
+
}
|
|
191
|
+
broadcastChannel = null;
|
|
192
|
+
}
|
|
193
|
+
};
|
|
194
|
+
const settle = (result) => {
|
|
195
|
+
if (settled) return;
|
|
196
|
+
settled = true;
|
|
197
|
+
cleanup();
|
|
198
|
+
resolve(result);
|
|
199
|
+
};
|
|
200
|
+
const handlePayload = (payload) => {
|
|
201
|
+
if (!payload || payload.type !== MCP_AUTH_CALLBACK_MESSAGE_TYPE) return;
|
|
202
|
+
if (payload.state && state && payload.state !== state) return;
|
|
203
|
+
if (payload.success) {
|
|
204
|
+
settle({ kind: "success" });
|
|
205
|
+
} else {
|
|
206
|
+
settle({
|
|
207
|
+
kind: "error",
|
|
208
|
+
error: payload.error ?? "Authentication failed in callback."
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
};
|
|
212
|
+
const messageHandler = (event) => {
|
|
213
|
+
if (expectedOrigin && event.origin !== expectedOrigin) return;
|
|
214
|
+
handlePayload(event.data);
|
|
215
|
+
};
|
|
216
|
+
const broadcastHandler = (event) => {
|
|
217
|
+
handlePayload(event.data);
|
|
218
|
+
};
|
|
219
|
+
const storageHandler = (event) => {
|
|
220
|
+
if (event.key !== tokensKey) return;
|
|
221
|
+
if (event.newValue) settle({ kind: "success" });
|
|
222
|
+
};
|
|
223
|
+
if (typeof window !== "undefined") {
|
|
224
|
+
window.addEventListener("message", messageHandler);
|
|
225
|
+
window.addEventListener("storage", storageHandler);
|
|
226
|
+
}
|
|
227
|
+
if (typeof BroadcastChannel !== "undefined") {
|
|
228
|
+
try {
|
|
229
|
+
broadcastChannel = new BroadcastChannel(MCP_AUTH_BROADCAST_CHANNEL);
|
|
230
|
+
broadcastChannel.addEventListener("message", broadcastHandler);
|
|
231
|
+
} catch {
|
|
232
|
+
broadcastChannel = null;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
if (popup) {
|
|
236
|
+
closeTimer = setInterval(() => {
|
|
237
|
+
if (settled) return;
|
|
238
|
+
let closed = false;
|
|
239
|
+
try {
|
|
240
|
+
closed = popup.closed;
|
|
241
|
+
} catch {
|
|
242
|
+
closed = false;
|
|
243
|
+
}
|
|
244
|
+
if (!closed) return;
|
|
245
|
+
if (closeTimer) {
|
|
246
|
+
clearInterval(closeTimer);
|
|
247
|
+
closeTimer = null;
|
|
248
|
+
}
|
|
249
|
+
if (hasStoredTokens(tokensKey)) {
|
|
250
|
+
settle({ kind: "success" });
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
graceTimer = setTimeout(() => {
|
|
254
|
+
settle(
|
|
255
|
+
hasStoredTokens(tokensKey) ? { kind: "success" } : { kind: "cancelled" }
|
|
256
|
+
);
|
|
257
|
+
}, closeGraceMs);
|
|
258
|
+
}, closePollMs);
|
|
259
|
+
}
|
|
260
|
+
timeoutTimer = setTimeout(() => {
|
|
261
|
+
settle(
|
|
262
|
+
hasStoredTokens(tokensKey) ? { kind: "success" } : { kind: "timeout" }
|
|
263
|
+
);
|
|
264
|
+
}, timeoutMs);
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
var MCP_AUTH_BROADCAST_CHANNEL, MCP_AUTH_CALLBACK_MESSAGE_TYPE;
|
|
268
|
+
var init_popup = __esm({
|
|
269
|
+
"src/auth/popup.ts"() {
|
|
270
|
+
"use strict";
|
|
271
|
+
MCP_AUTH_BROADCAST_CHANNEL = "mcp_auth_callback";
|
|
272
|
+
MCP_AUTH_CALLBACK_MESSAGE_TYPE = "mcp_auth_callback";
|
|
273
|
+
}
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
// src/auth/flow.ts
|
|
277
|
+
import {
|
|
278
|
+
auth,
|
|
279
|
+
InsufficientScopeError,
|
|
280
|
+
UnauthorizedError
|
|
281
|
+
} from "@modelcontextprotocol/client";
|
|
282
|
+
function isUnauthorized(err, depth = 0) {
|
|
283
|
+
if (!err || depth > 5) return false;
|
|
284
|
+
if (err instanceof UnauthorizedError) return true;
|
|
285
|
+
if (err instanceof Error) {
|
|
286
|
+
const code = err.code;
|
|
287
|
+
if (code === 401) return true;
|
|
288
|
+
if (err.name === "UnauthorizedError") return true;
|
|
289
|
+
const message = err.message ?? "";
|
|
290
|
+
if (message.includes("401") || message.includes("Unauthorized")) {
|
|
291
|
+
return true;
|
|
292
|
+
}
|
|
293
|
+
if (err.cause && isUnauthorized(err.cause, depth + 1)) return true;
|
|
294
|
+
const data = err.data;
|
|
295
|
+
if (data?.cause && isUnauthorized(data.cause, depth + 1)) return true;
|
|
296
|
+
}
|
|
297
|
+
return false;
|
|
298
|
+
}
|
|
299
|
+
function isOAuthInteractionRequired(err, depth = 0) {
|
|
300
|
+
if (!err || depth > 5) return false;
|
|
301
|
+
if (err instanceof InsufficientScopeError || err instanceof UnauthorizedError) {
|
|
302
|
+
return true;
|
|
303
|
+
}
|
|
304
|
+
if (err instanceof Error) {
|
|
305
|
+
if (err.name === "InsufficientScopeError" || err.name === "UnauthorizedError") {
|
|
306
|
+
return true;
|
|
307
|
+
}
|
|
308
|
+
if (err.cause && isOAuthInteractionRequired(err.cause, depth + 1)) {
|
|
309
|
+
return true;
|
|
310
|
+
}
|
|
311
|
+
const data = err.data;
|
|
312
|
+
if (data?.cause && isOAuthInteractionRequired(data.cause, depth + 1)) {
|
|
313
|
+
return true;
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
return false;
|
|
317
|
+
}
|
|
318
|
+
async function completeOAuthFlow(provider, serverUrl, options = {}) {
|
|
319
|
+
const flowProvider = provider;
|
|
320
|
+
const timeoutMs = options.timeoutMs ?? DEFAULT_AUTH_TIMEOUT_MS;
|
|
321
|
+
const fetchFn = options.fetchFn ?? flowProvider.getProxyFetch?.() ?? void 0;
|
|
322
|
+
if (!flowProvider.hasPendingFlow) {
|
|
323
|
+
const result = await auth(provider, { serverUrl, fetchFn });
|
|
324
|
+
if (result === "AUTHORIZED") return;
|
|
325
|
+
if (result !== "REDIRECT") {
|
|
326
|
+
throw new Error(`Unexpected OAuth auth() result: ${result}`);
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
if (flowProvider.preventAutoAuth === true && typeof flowProvider.startAuthorization === "function") {
|
|
330
|
+
flowProvider.startAuthorization();
|
|
331
|
+
}
|
|
332
|
+
if (typeof flowProvider.getAuthorizationResponse === "function" || typeof flowProvider.getAuthorizationCode === "function") {
|
|
333
|
+
const response = typeof flowProvider.getAuthorizationResponse === "function" ? await flowProvider.getAuthorizationResponse() : { code: await flowProvider.getAuthorizationCode() };
|
|
334
|
+
if (options.finishAuthorization) {
|
|
335
|
+
await options.finishAuthorization(response.code, response.iss);
|
|
336
|
+
} else {
|
|
337
|
+
await auth(provider, {
|
|
338
|
+
serverUrl,
|
|
339
|
+
authorizationCode: response.code,
|
|
340
|
+
...response.iss !== void 0 ? { iss: response.iss } : {},
|
|
341
|
+
fetchFn
|
|
342
|
+
});
|
|
343
|
+
}
|
|
344
|
+
return;
|
|
345
|
+
}
|
|
346
|
+
await waitForBrowserAuthComplete(flowProvider, timeoutMs);
|
|
347
|
+
}
|
|
348
|
+
async function waitForBrowserAuthComplete(provider, timeoutMs) {
|
|
349
|
+
if (typeof window === "undefined") {
|
|
350
|
+
throw new Error(
|
|
351
|
+
"OAuth redirect requires a browser environment or a provider with getAuthorizationCode()"
|
|
352
|
+
);
|
|
353
|
+
}
|
|
354
|
+
if (provider.useRedirectFlow) {
|
|
355
|
+
await new Promise(() => {
|
|
356
|
+
});
|
|
357
|
+
return;
|
|
358
|
+
}
|
|
359
|
+
const tokensKey = provider.getKey?.("tokens");
|
|
360
|
+
if (!tokensKey) {
|
|
361
|
+
throw new Error(
|
|
362
|
+
"Browser OAuth provider must expose getKey() for token storage"
|
|
363
|
+
);
|
|
364
|
+
}
|
|
365
|
+
let state = null;
|
|
366
|
+
const authUrl = provider.getLastAttemptedAuthUrl?.();
|
|
367
|
+
if (authUrl) {
|
|
368
|
+
try {
|
|
369
|
+
state = new URL(authUrl).searchParams.get("state");
|
|
370
|
+
} catch {
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
try {
|
|
374
|
+
const result = await runAuthPopup({
|
|
375
|
+
popup: null,
|
|
376
|
+
state,
|
|
377
|
+
tokensKey,
|
|
378
|
+
timeoutMs
|
|
379
|
+
});
|
|
380
|
+
switch (result.kind) {
|
|
381
|
+
case "success":
|
|
382
|
+
return;
|
|
383
|
+
case "cancelled":
|
|
384
|
+
throw new Error("OAuth authentication was cancelled.");
|
|
385
|
+
case "timeout":
|
|
386
|
+
throw new Error(
|
|
387
|
+
`OAuth callback not received within ${timeoutMs}ms. Ensure /oauth/callback calls onMcpAuthorization().`
|
|
388
|
+
);
|
|
389
|
+
case "error":
|
|
390
|
+
throw new Error(result.error);
|
|
391
|
+
default:
|
|
392
|
+
throw new Error("Unexpected OAuth popup result");
|
|
393
|
+
}
|
|
394
|
+
} finally {
|
|
395
|
+
provider.markFlowComplete?.();
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
var DEFAULT_AUTH_TIMEOUT_MS;
|
|
399
|
+
var init_flow = __esm({
|
|
400
|
+
"src/auth/flow.ts"() {
|
|
401
|
+
"use strict";
|
|
402
|
+
init_popup();
|
|
403
|
+
DEFAULT_AUTH_TIMEOUT_MS = 5 * 6e4;
|
|
404
|
+
}
|
|
405
|
+
});
|
|
406
|
+
|
|
145
407
|
// src/utils/json-schema-validator.ts
|
|
146
408
|
import {
|
|
147
409
|
CfWorkerJsonSchemaValidator
|
|
@@ -190,6 +452,7 @@ var init_base = __esm({
|
|
|
190
452
|
"src/transport/base.ts"() {
|
|
191
453
|
"use strict";
|
|
192
454
|
init_logging();
|
|
455
|
+
init_flow();
|
|
193
456
|
init_connector_telemetry();
|
|
194
457
|
passthroughResultSchema = {
|
|
195
458
|
"~standard": {
|
|
@@ -204,6 +467,7 @@ var init_base = __esm({
|
|
|
204
467
|
toolsCache = null;
|
|
205
468
|
capabilitiesCache = null;
|
|
206
469
|
serverInfoCache = null;
|
|
470
|
+
authorizationCache;
|
|
207
471
|
connected = false;
|
|
208
472
|
opts;
|
|
209
473
|
notificationHandlers = [];
|
|
@@ -467,6 +731,28 @@ var init_base = __esm({
|
|
|
467
731
|
"setupElicitationHandler: Elicitation handler registered successfully"
|
|
468
732
|
);
|
|
469
733
|
}
|
|
734
|
+
/**
|
|
735
|
+
* Run one logical MCP operation. HTTP connectors override this host seam to
|
|
736
|
+
* finish an SDK-started interactive OAuth flow and retry exactly once.
|
|
737
|
+
*/
|
|
738
|
+
async executeRequest(operation) {
|
|
739
|
+
return operation();
|
|
740
|
+
}
|
|
741
|
+
/** OAuth state discovered for the active connection, when available. */
|
|
742
|
+
get authorization() {
|
|
743
|
+
return this.authorizationCache;
|
|
744
|
+
}
|
|
745
|
+
/**
|
|
746
|
+
* Discover optional authorization metadata without delaying connection
|
|
747
|
+
* readiness. HTTP connectors override this with RFC 9728 discovery.
|
|
748
|
+
*/
|
|
749
|
+
async discoverAuthorization() {
|
|
750
|
+
return this.authorization;
|
|
751
|
+
}
|
|
752
|
+
/** Start optional OAuth for a connected mixed-auth server. */
|
|
753
|
+
async authenticate() {
|
|
754
|
+
throw new Error("This connector does not support interactive OAuth");
|
|
755
|
+
}
|
|
470
756
|
/**
|
|
471
757
|
* Disconnects the SDK client and releases transport resources.
|
|
472
758
|
*
|
|
@@ -514,13 +800,13 @@ var init_base = __esm({
|
|
|
514
800
|
icons: serverInfo.icons
|
|
515
801
|
} : null;
|
|
516
802
|
try {
|
|
517
|
-
const listToolsRes = await this.
|
|
518
|
-
void 0,
|
|
519
|
-
defaultRequestOptions
|
|
803
|
+
const listToolsRes = await this.executeRequest(
|
|
804
|
+
() => this.client.listTools(void 0, defaultRequestOptions)
|
|
520
805
|
);
|
|
521
806
|
this.toolsCache = listToolsRes.tools ?? [];
|
|
522
807
|
logger.debug(`Fetched ${this.toolsCache.length} tools from server`);
|
|
523
808
|
} catch (err) {
|
|
809
|
+
if (isOAuthInteractionRequired(err)) throw err;
|
|
524
810
|
const error = err;
|
|
525
811
|
if (error.code === -32601) {
|
|
526
812
|
logger.debug("Server does not implement tools/list, assuming no tools");
|
|
@@ -594,9 +880,8 @@ var init_base = __esm({
|
|
|
594
880
|
const progressHandler = enhancedOptions?.onprogress;
|
|
595
881
|
if (progressHandler) this.activeProgressHandlers.add(progressHandler);
|
|
596
882
|
try {
|
|
597
|
-
const res = await this.
|
|
598
|
-
{ name, arguments: args },
|
|
599
|
-
enhancedOptions
|
|
883
|
+
const res = await this.executeRequest(
|
|
884
|
+
() => this.client.callTool({ name, arguments: args }, enhancedOptions)
|
|
600
885
|
);
|
|
601
886
|
logger.debug(`Tool '${name}' returned`, res);
|
|
602
887
|
return res;
|
|
@@ -616,7 +901,9 @@ var init_base = __esm({
|
|
|
616
901
|
throw new Error("MCP client is not connected");
|
|
617
902
|
}
|
|
618
903
|
logger.debug("[listTools] Fetching fresh tools from server...");
|
|
619
|
-
const result = await this.
|
|
904
|
+
const result = await this.executeRequest(
|
|
905
|
+
() => this.client.listTools(void 0, options)
|
|
906
|
+
);
|
|
620
907
|
const tools = result.tools ? [...result.tools] : [];
|
|
621
908
|
logger.debug(
|
|
622
909
|
`[listTools] Returned ${tools.length} tools:`,
|
|
@@ -636,7 +923,9 @@ var init_base = __esm({
|
|
|
636
923
|
throw new Error("MCP client is not connected");
|
|
637
924
|
}
|
|
638
925
|
logger.debug("Listing resources", cursor ? `with cursor: ${cursor}` : "");
|
|
639
|
-
return await this.
|
|
926
|
+
return await this.executeRequest(
|
|
927
|
+
() => this.client.listResources({ cursor }, options)
|
|
928
|
+
);
|
|
640
929
|
}
|
|
641
930
|
/**
|
|
642
931
|
* List all resources from the server, automatically handling pagination
|
|
@@ -654,14 +943,16 @@ var init_base = __esm({
|
|
|
654
943
|
}
|
|
655
944
|
try {
|
|
656
945
|
logger.debug("Listing all resources (with auto-pagination)");
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
946
|
+
return await this.executeRequest(async () => {
|
|
947
|
+
const allResources = [];
|
|
948
|
+
let cursor = void 0;
|
|
949
|
+
do {
|
|
950
|
+
const result = await this.client.listResources({ cursor }, options);
|
|
951
|
+
allResources.push(...result.resources || []);
|
|
952
|
+
cursor = result.nextCursor;
|
|
953
|
+
} while (cursor);
|
|
954
|
+
return { resources: allResources };
|
|
955
|
+
});
|
|
665
956
|
} catch (err) {
|
|
666
957
|
const error = err;
|
|
667
958
|
if (error.code === -32601) {
|
|
@@ -682,7 +973,9 @@ var init_base = __esm({
|
|
|
682
973
|
throw new Error("MCP client is not connected");
|
|
683
974
|
}
|
|
684
975
|
logger.debug("Listing resource templates");
|
|
685
|
-
return await this.
|
|
976
|
+
return await this.executeRequest(
|
|
977
|
+
() => this.client.listResourceTemplates(void 0, options)
|
|
978
|
+
);
|
|
686
979
|
}
|
|
687
980
|
/**
|
|
688
981
|
* Request completion suggestions for a prompt or resource template argument
|
|
@@ -696,7 +989,9 @@ var init_base = __esm({
|
|
|
696
989
|
throw new Error("MCP client is not connected");
|
|
697
990
|
}
|
|
698
991
|
logger.debug("[complete] Requesting completions for:", params.ref);
|
|
699
|
-
const result = await this.
|
|
992
|
+
const result = await this.executeRequest(
|
|
993
|
+
() => this.client.complete(params, options)
|
|
994
|
+
);
|
|
700
995
|
logger.debug(
|
|
701
996
|
`[complete] Received ${result.completion.values.length} suggestions`
|
|
702
997
|
);
|
|
@@ -714,7 +1009,9 @@ var init_base = __esm({
|
|
|
714
1009
|
throw new Error("MCP client is not connected");
|
|
715
1010
|
}
|
|
716
1011
|
logger.debug(`Reading resource ${uri}`);
|
|
717
|
-
const res = await this.
|
|
1012
|
+
const res = await this.executeRequest(
|
|
1013
|
+
() => this.client.readResource({ uri }, options)
|
|
1014
|
+
);
|
|
718
1015
|
return res;
|
|
719
1016
|
}
|
|
720
1017
|
/**
|
|
@@ -728,7 +1025,9 @@ var init_base = __esm({
|
|
|
728
1025
|
throw new Error("MCP client is not connected");
|
|
729
1026
|
}
|
|
730
1027
|
logger.debug(`Subscribing to resource: ${uri}`);
|
|
731
|
-
return await this.
|
|
1028
|
+
return await this.executeRequest(
|
|
1029
|
+
() => this.client.subscribeResource({ uri }, options)
|
|
1030
|
+
);
|
|
732
1031
|
}
|
|
733
1032
|
/**
|
|
734
1033
|
* Unsubscribe from resource updates
|
|
@@ -741,7 +1040,9 @@ var init_base = __esm({
|
|
|
741
1040
|
throw new Error("MCP client is not connected");
|
|
742
1041
|
}
|
|
743
1042
|
logger.debug(`Unsubscribing from resource: ${uri}`);
|
|
744
|
-
return await this.
|
|
1043
|
+
return await this.executeRequest(
|
|
1044
|
+
() => this.client.unsubscribeResource({ uri }, options)
|
|
1045
|
+
);
|
|
745
1046
|
}
|
|
746
1047
|
/**
|
|
747
1048
|
* Lists prompts exposed by the server.
|
|
@@ -758,7 +1059,7 @@ var init_base = __esm({
|
|
|
758
1059
|
}
|
|
759
1060
|
try {
|
|
760
1061
|
logger.debug("Listing prompts");
|
|
761
|
-
return await this.client.listPrompts();
|
|
1062
|
+
return await this.executeRequest(() => this.client.listPrompts());
|
|
762
1063
|
} catch (err) {
|
|
763
1064
|
const error = err;
|
|
764
1065
|
if (error.code === -32601) {
|
|
@@ -780,7 +1081,9 @@ var init_base = __esm({
|
|
|
780
1081
|
throw new Error("MCP client is not connected");
|
|
781
1082
|
}
|
|
782
1083
|
logger.debug(`Getting prompt ${name}`);
|
|
783
|
-
return await this.
|
|
1084
|
+
return await this.executeRequest(
|
|
1085
|
+
() => this.client.getPrompt({ name, arguments: args })
|
|
1086
|
+
);
|
|
784
1087
|
}
|
|
785
1088
|
/**
|
|
786
1089
|
* Sends a raw, potentially non-standard request through the SDK client.
|
|
@@ -795,10 +1098,12 @@ var init_base = __esm({
|
|
|
795
1098
|
throw new Error("MCP client is not connected");
|
|
796
1099
|
}
|
|
797
1100
|
logger.debug(`Sending raw request '${method}' with params`, params);
|
|
798
|
-
return await this.
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
1101
|
+
return await this.executeRequest(
|
|
1102
|
+
() => this.client.request(
|
|
1103
|
+
{ method, params: params ?? {} },
|
|
1104
|
+
passthroughResultSchema,
|
|
1105
|
+
options
|
|
1106
|
+
)
|
|
802
1107
|
);
|
|
803
1108
|
}
|
|
804
1109
|
/**
|
|
@@ -831,6 +1136,7 @@ var init_base = __esm({
|
|
|
831
1136
|
}
|
|
832
1137
|
}
|
|
833
1138
|
this.toolsCache = null;
|
|
1139
|
+
this.authorizationCache = void 0;
|
|
834
1140
|
if (issues.length) {
|
|
835
1141
|
logger.warn(`Resource cleanup finished with ${issues.length} issue(s)`);
|
|
836
1142
|
}
|
|
@@ -1219,7 +1525,7 @@ init_connector_telemetry();
|
|
|
1219
1525
|
init_logging();
|
|
1220
1526
|
|
|
1221
1527
|
// src/utils/version.ts
|
|
1222
|
-
var VERSION = "2.1.
|
|
1528
|
+
var VERSION = "2.1.1-canary.1";
|
|
1223
1529
|
function getPackageVersion() {
|
|
1224
1530
|
return VERSION;
|
|
1225
1531
|
}
|
|
@@ -1618,396 +1924,173 @@ var Telemetry = class _Telemetry {
|
|
|
1618
1924
|
const p = capturePostHog({
|
|
1619
1925
|
host: HOST,
|
|
1620
1926
|
apiKey: PROJECT_API_KEY,
|
|
1621
|
-
event: event.name,
|
|
1622
|
-
distinctId: currentUserId,
|
|
1623
|
-
properties
|
|
1624
|
-
});
|
|
1625
|
-
this._pending.add(p);
|
|
1626
|
-
void p.finally(() => this._pending.delete(p));
|
|
1627
|
-
}
|
|
1628
|
-
async trackAgentExecution(data) {
|
|
1629
|
-
if (!this.isEnabled) return;
|
|
1630
|
-
await this.capture(new MCPAgentExecutionEvent(data));
|
|
1631
|
-
}
|
|
1632
|
-
async trackMCPClientInit(data) {
|
|
1633
|
-
if (!this.isEnabled) return;
|
|
1634
|
-
await this.capture(new MCPClientInitEvent(data));
|
|
1635
|
-
}
|
|
1636
|
-
async trackConnectorInit(data) {
|
|
1637
|
-
if (!this.isEnabled) return;
|
|
1638
|
-
await this.capture(new ConnectorInitEvent(data));
|
|
1639
|
-
}
|
|
1640
|
-
async trackClientAddServer(serverName, serverConfig) {
|
|
1641
|
-
if (!this.isEnabled) return;
|
|
1642
|
-
await this.capture(new ClientAddServerEvent({ serverName, serverConfig }));
|
|
1643
|
-
}
|
|
1644
|
-
async trackClientRemoveServer(serverName) {
|
|
1645
|
-
if (!this.isEnabled) return;
|
|
1646
|
-
await this.capture(new ClientRemoveServerEvent({ serverName }));
|
|
1647
|
-
}
|
|
1648
|
-
async trackUseMcpConnection(data) {
|
|
1649
|
-
if (!this.isEnabled) return;
|
|
1650
|
-
await this.capture({
|
|
1651
|
-
name: "usemcp_connection",
|
|
1652
|
-
properties: {
|
|
1653
|
-
url_domain: new URL(data.url).hostname,
|
|
1654
|
-
transport_type: data.transportType,
|
|
1655
|
-
success: data.success,
|
|
1656
|
-
error_type: data.errorType ?? null,
|
|
1657
|
-
connection_time_ms: data.connectionTimeMs ?? null,
|
|
1658
|
-
has_oauth: data.hasOAuth,
|
|
1659
|
-
has_sampling: data.hasSampling,
|
|
1660
|
-
has_elicitation: data.hasElicitation
|
|
1661
|
-
}
|
|
1662
|
-
});
|
|
1663
|
-
}
|
|
1664
|
-
async trackUseMcpToolCall(data) {
|
|
1665
|
-
if (!this.isEnabled) return;
|
|
1666
|
-
await this.capture({
|
|
1667
|
-
name: "usemcp_tool_call",
|
|
1668
|
-
properties: {
|
|
1669
|
-
tool_name: data.toolName,
|
|
1670
|
-
success: data.success,
|
|
1671
|
-
error_type: data.errorType ?? null,
|
|
1672
|
-
execution_time_ms: data.executionTimeMs ?? null
|
|
1673
|
-
}
|
|
1674
|
-
});
|
|
1675
|
-
}
|
|
1676
|
-
async trackUseMcpResourceRead(data) {
|
|
1677
|
-
if (!this.isEnabled) return;
|
|
1678
|
-
await this.capture({
|
|
1679
|
-
name: "usemcp_resource_read",
|
|
1680
|
-
properties: {
|
|
1681
|
-
resource_uri_scheme: data.resourceUri.split(":")[0],
|
|
1682
|
-
success: data.success,
|
|
1683
|
-
error_type: data.errorType ?? null
|
|
1684
|
-
}
|
|
1685
|
-
});
|
|
1686
|
-
}
|
|
1687
|
-
identify(userId, properties) {
|
|
1688
|
-
this._currUserId = userId;
|
|
1689
|
-
this._storage?.setUserId(userId);
|
|
1690
|
-
if (this._telemetryEnabled) {
|
|
1691
|
-
void capturePostHog({
|
|
1692
|
-
host: HOST,
|
|
1693
|
-
apiKey: PROJECT_API_KEY,
|
|
1694
|
-
event: "$identify",
|
|
1695
|
-
distinctId: userId,
|
|
1696
|
-
properties: { $set: properties ?? {} }
|
|
1697
|
-
});
|
|
1698
|
-
}
|
|
1699
|
-
}
|
|
1700
|
-
reset() {
|
|
1701
|
-
this._currUserId = null;
|
|
1702
|
-
}
|
|
1703
|
-
flush() {
|
|
1704
|
-
void Promise.allSettled([...this._pending]);
|
|
1705
|
-
}
|
|
1706
|
-
async shutdown() {
|
|
1707
|
-
try {
|
|
1708
|
-
await Promise.allSettled([...this._pending]);
|
|
1709
|
-
logger.debug("Telemetry fetch captures flushed");
|
|
1710
|
-
} catch (e) {
|
|
1711
|
-
logger.debug(`Error flushing telemetry captures: ${e}`);
|
|
1712
|
-
}
|
|
1713
|
-
}
|
|
1714
|
-
};
|
|
1715
|
-
var Tel = Telemetry;
|
|
1716
|
-
function setTelemetrySource(source) {
|
|
1717
|
-
Tel.getInstance().setSource(source);
|
|
1718
|
-
}
|
|
1719
|
-
function setProductVersion(version) {
|
|
1720
|
-
Tel.getInstance().setProductVersion(version);
|
|
1721
|
-
}
|
|
1722
|
-
|
|
1723
|
-
// src/telemetry/telemetry-node.ts
|
|
1724
|
-
function getCacheHome(os, path2) {
|
|
1725
|
-
const envVar = process.env.XDG_CACHE_HOME;
|
|
1726
|
-
if (envVar && path2.isAbsolute(envVar)) {
|
|
1727
|
-
return envVar;
|
|
1728
|
-
}
|
|
1729
|
-
const homeDir = os.homedir();
|
|
1730
|
-
if (process.platform === "win32") {
|
|
1731
|
-
const appdata = process.env.LOCALAPPDATA || process.env.APPDATA;
|
|
1732
|
-
if (appdata) return appdata;
|
|
1733
|
-
return path2.join(homeDir, "AppData", "Local");
|
|
1734
|
-
}
|
|
1735
|
-
if (process.platform === "darwin") {
|
|
1736
|
-
return path2.join(homeDir, "Library", "Caches");
|
|
1737
|
-
}
|
|
1738
|
-
return path2.join(homeDir, ".cache");
|
|
1739
|
-
}
|
|
1740
|
-
function createFsStorage() {
|
|
1741
|
-
let fs2;
|
|
1742
|
-
let os;
|
|
1743
|
-
let path2;
|
|
1744
|
-
try {
|
|
1745
|
-
fs2 = __require("fs");
|
|
1746
|
-
os = __require("os");
|
|
1747
|
-
path2 = __require("path");
|
|
1748
|
-
} catch {
|
|
1749
|
-
return {
|
|
1750
|
-
getUserId: () => null,
|
|
1751
|
-
setUserId: () => void 0
|
|
1752
|
-
};
|
|
1753
|
-
}
|
|
1754
|
-
const cacheHome = getCacheHome(os, path2);
|
|
1755
|
-
const userIdPath = path2.join(cacheHome, "mcp_use_3", "telemetry_user_id");
|
|
1756
|
-
return {
|
|
1757
|
-
getUserId() {
|
|
1758
|
-
try {
|
|
1759
|
-
if (!fs2.existsSync(userIdPath)) return null;
|
|
1760
|
-
return fs2.readFileSync(userIdPath, "utf-8").trim() || null;
|
|
1761
|
-
} catch {
|
|
1762
|
-
return null;
|
|
1763
|
-
}
|
|
1764
|
-
},
|
|
1765
|
-
setUserId(id) {
|
|
1766
|
-
try {
|
|
1767
|
-
fs2.mkdirSync(path2.dirname(userIdPath), { recursive: true });
|
|
1768
|
-
fs2.writeFileSync(userIdPath, id);
|
|
1769
|
-
} catch {
|
|
1770
|
-
}
|
|
1771
|
-
}
|
|
1772
|
-
};
|
|
1773
|
-
}
|
|
1774
|
-
configureTelemetryStorage(createFsStorage());
|
|
1775
|
-
|
|
1776
|
-
// src/telemetry/configure-node.ts
|
|
1777
|
-
setClientTelemetryTracker({
|
|
1778
|
-
addServer: (name, config) => Telemetry.getInstance().trackClientAddServer(name, config).catch(() => void 0),
|
|
1779
|
-
removeServer: (name) => Telemetry.getInstance().trackClientRemoveServer(name).catch(() => void 0)
|
|
1780
|
-
});
|
|
1781
|
-
setConnectorTelemetryTracker(
|
|
1782
|
-
(data) => Telemetry.getInstance().trackConnectorInit(data).catch(() => void 0)
|
|
1783
|
-
);
|
|
1784
|
-
|
|
1785
|
-
// src/index.ts
|
|
1786
|
-
import { auth as auth2, UnauthorizedError as UnauthorizedError3 } from "@modelcontextprotocol/client";
|
|
1787
|
-
|
|
1788
|
-
// src/auth/flow.ts
|
|
1789
|
-
import {
|
|
1790
|
-
auth,
|
|
1791
|
-
UnauthorizedError
|
|
1792
|
-
} from "@modelcontextprotocol/client";
|
|
1793
|
-
|
|
1794
|
-
// src/auth/popup.ts
|
|
1795
|
-
var MCP_AUTH_BROADCAST_CHANNEL = "mcp_auth_callback";
|
|
1796
|
-
var MCP_AUTH_CALLBACK_MESSAGE_TYPE = "mcp_auth_callback";
|
|
1797
|
-
function hasStoredTokens(tokensKey) {
|
|
1798
|
-
try {
|
|
1799
|
-
return typeof localStorage !== "undefined" && !!localStorage.getItem(tokensKey);
|
|
1800
|
-
} catch {
|
|
1801
|
-
return false;
|
|
1802
|
-
}
|
|
1803
|
-
}
|
|
1804
|
-
function runAuthPopup({
|
|
1805
|
-
popup,
|
|
1806
|
-
state,
|
|
1807
|
-
tokensKey,
|
|
1808
|
-
timeoutMs = 5 * 6e4,
|
|
1809
|
-
closePollMs = 1e3,
|
|
1810
|
-
closeGraceMs = 2e4,
|
|
1811
|
-
expectedOrigin = typeof window !== "undefined" ? window.location.origin : ""
|
|
1812
|
-
}) {
|
|
1813
|
-
return new Promise((resolve) => {
|
|
1814
|
-
let settled = false;
|
|
1815
|
-
let closeTimer = null;
|
|
1816
|
-
let timeoutTimer = null;
|
|
1817
|
-
let graceTimer = null;
|
|
1818
|
-
let broadcastChannel = null;
|
|
1819
|
-
const cleanup = () => {
|
|
1820
|
-
if (closeTimer) {
|
|
1821
|
-
clearInterval(closeTimer);
|
|
1822
|
-
closeTimer = null;
|
|
1823
|
-
}
|
|
1824
|
-
if (timeoutTimer) {
|
|
1825
|
-
clearTimeout(timeoutTimer);
|
|
1826
|
-
timeoutTimer = null;
|
|
1827
|
-
}
|
|
1828
|
-
if (graceTimer) {
|
|
1829
|
-
clearTimeout(graceTimer);
|
|
1830
|
-
graceTimer = null;
|
|
1831
|
-
}
|
|
1832
|
-
if (typeof window !== "undefined") {
|
|
1833
|
-
window.removeEventListener("message", messageHandler);
|
|
1834
|
-
window.removeEventListener("storage", storageHandler);
|
|
1835
|
-
}
|
|
1836
|
-
if (broadcastChannel) {
|
|
1837
|
-
try {
|
|
1838
|
-
broadcastChannel.removeEventListener("message", broadcastHandler);
|
|
1839
|
-
broadcastChannel.close();
|
|
1840
|
-
} catch {
|
|
1841
|
-
}
|
|
1842
|
-
broadcastChannel = null;
|
|
1843
|
-
}
|
|
1844
|
-
};
|
|
1845
|
-
const settle = (result) => {
|
|
1846
|
-
if (settled) return;
|
|
1847
|
-
settled = true;
|
|
1848
|
-
cleanup();
|
|
1849
|
-
resolve(result);
|
|
1850
|
-
};
|
|
1851
|
-
const handlePayload = (payload) => {
|
|
1852
|
-
if (!payload || payload.type !== MCP_AUTH_CALLBACK_MESSAGE_TYPE) return;
|
|
1853
|
-
if (payload.state && state && payload.state !== state) return;
|
|
1854
|
-
if (payload.success) {
|
|
1855
|
-
settle({ kind: "success" });
|
|
1856
|
-
} else {
|
|
1857
|
-
settle({
|
|
1858
|
-
kind: "error",
|
|
1859
|
-
error: payload.error ?? "Authentication failed in callback."
|
|
1860
|
-
});
|
|
1861
|
-
}
|
|
1862
|
-
};
|
|
1863
|
-
const messageHandler = (event) => {
|
|
1864
|
-
if (expectedOrigin && event.origin !== expectedOrigin) return;
|
|
1865
|
-
handlePayload(event.data);
|
|
1866
|
-
};
|
|
1867
|
-
const broadcastHandler = (event) => {
|
|
1868
|
-
handlePayload(event.data);
|
|
1869
|
-
};
|
|
1870
|
-
const storageHandler = (event) => {
|
|
1871
|
-
if (event.key !== tokensKey) return;
|
|
1872
|
-
if (event.newValue) settle({ kind: "success" });
|
|
1873
|
-
};
|
|
1874
|
-
if (typeof window !== "undefined") {
|
|
1875
|
-
window.addEventListener("message", messageHandler);
|
|
1876
|
-
window.addEventListener("storage", storageHandler);
|
|
1877
|
-
}
|
|
1878
|
-
if (typeof BroadcastChannel !== "undefined") {
|
|
1879
|
-
try {
|
|
1880
|
-
broadcastChannel = new BroadcastChannel(MCP_AUTH_BROADCAST_CHANNEL);
|
|
1881
|
-
broadcastChannel.addEventListener("message", broadcastHandler);
|
|
1882
|
-
} catch {
|
|
1883
|
-
broadcastChannel = null;
|
|
1884
|
-
}
|
|
1885
|
-
}
|
|
1886
|
-
if (popup) {
|
|
1887
|
-
closeTimer = setInterval(() => {
|
|
1888
|
-
if (settled) return;
|
|
1889
|
-
let closed = false;
|
|
1890
|
-
try {
|
|
1891
|
-
closed = popup.closed;
|
|
1892
|
-
} catch {
|
|
1893
|
-
closed = false;
|
|
1894
|
-
}
|
|
1895
|
-
if (!closed) return;
|
|
1896
|
-
if (closeTimer) {
|
|
1897
|
-
clearInterval(closeTimer);
|
|
1898
|
-
closeTimer = null;
|
|
1899
|
-
}
|
|
1900
|
-
if (hasStoredTokens(tokensKey)) {
|
|
1901
|
-
settle({ kind: "success" });
|
|
1902
|
-
return;
|
|
1903
|
-
}
|
|
1904
|
-
graceTimer = setTimeout(() => {
|
|
1905
|
-
settle(
|
|
1906
|
-
hasStoredTokens(tokensKey) ? { kind: "success" } : { kind: "cancelled" }
|
|
1907
|
-
);
|
|
1908
|
-
}, closeGraceMs);
|
|
1909
|
-
}, closePollMs);
|
|
1910
|
-
}
|
|
1911
|
-
timeoutTimer = setTimeout(() => {
|
|
1912
|
-
settle(
|
|
1913
|
-
hasStoredTokens(tokensKey) ? { kind: "success" } : { kind: "timeout" }
|
|
1914
|
-
);
|
|
1915
|
-
}, timeoutMs);
|
|
1916
|
-
});
|
|
1917
|
-
}
|
|
1918
|
-
|
|
1919
|
-
// src/auth/flow.ts
|
|
1920
|
-
var DEFAULT_AUTH_TIMEOUT_MS = 5 * 6e4;
|
|
1921
|
-
function isUnauthorized(err, depth = 0) {
|
|
1922
|
-
if (!err || depth > 5) return false;
|
|
1923
|
-
if (err instanceof UnauthorizedError) return true;
|
|
1924
|
-
if (err instanceof Error) {
|
|
1925
|
-
const code = err.code;
|
|
1926
|
-
if (code === 401) return true;
|
|
1927
|
-
if (err.name === "UnauthorizedError") return true;
|
|
1928
|
-
const message = err.message ?? "";
|
|
1929
|
-
if (message.includes("401") || message.includes("Unauthorized")) {
|
|
1930
|
-
return true;
|
|
1931
|
-
}
|
|
1932
|
-
if (err.cause && isUnauthorized(err.cause, depth + 1)) return true;
|
|
1933
|
-
const data = err.data;
|
|
1934
|
-
if (data?.cause && isUnauthorized(data.cause, depth + 1)) return true;
|
|
1927
|
+
event: event.name,
|
|
1928
|
+
distinctId: currentUserId,
|
|
1929
|
+
properties
|
|
1930
|
+
});
|
|
1931
|
+
this._pending.add(p);
|
|
1932
|
+
void p.finally(() => this._pending.delete(p));
|
|
1935
1933
|
}
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
const flowProvider = provider;
|
|
1940
|
-
const timeoutMs = options.timeoutMs ?? DEFAULT_AUTH_TIMEOUT_MS;
|
|
1941
|
-
const fetchFn = options.fetchFn ?? flowProvider.getProxyFetch?.() ?? void 0;
|
|
1942
|
-
if (!flowProvider.hasPendingFlow) {
|
|
1943
|
-
const result = await auth(provider, { serverUrl, fetchFn });
|
|
1944
|
-
if (result === "AUTHORIZED") return;
|
|
1945
|
-
if (result !== "REDIRECT") {
|
|
1946
|
-
throw new Error(`Unexpected OAuth auth() result: ${result}`);
|
|
1947
|
-
}
|
|
1934
|
+
async trackAgentExecution(data) {
|
|
1935
|
+
if (!this.isEnabled) return;
|
|
1936
|
+
await this.capture(new MCPAgentExecutionEvent(data));
|
|
1948
1937
|
}
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
await
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1938
|
+
async trackMCPClientInit(data) {
|
|
1939
|
+
if (!this.isEnabled) return;
|
|
1940
|
+
await this.capture(new MCPClientInitEvent(data));
|
|
1941
|
+
}
|
|
1942
|
+
async trackConnectorInit(data) {
|
|
1943
|
+
if (!this.isEnabled) return;
|
|
1944
|
+
await this.capture(new ConnectorInitEvent(data));
|
|
1945
|
+
}
|
|
1946
|
+
async trackClientAddServer(serverName, serverConfig) {
|
|
1947
|
+
if (!this.isEnabled) return;
|
|
1948
|
+
await this.capture(new ClientAddServerEvent({ serverName, serverConfig }));
|
|
1949
|
+
}
|
|
1950
|
+
async trackClientRemoveServer(serverName) {
|
|
1951
|
+
if (!this.isEnabled) return;
|
|
1952
|
+
await this.capture(new ClientRemoveServerEvent({ serverName }));
|
|
1953
|
+
}
|
|
1954
|
+
async trackUseMcpConnection(data) {
|
|
1955
|
+
if (!this.isEnabled) return;
|
|
1956
|
+
await this.capture({
|
|
1957
|
+
name: "usemcp_connection",
|
|
1958
|
+
properties: {
|
|
1959
|
+
url_domain: new URL(data.url).hostname,
|
|
1960
|
+
transport_type: data.transportType,
|
|
1961
|
+
success: data.success,
|
|
1962
|
+
error_type: data.errorType ?? null,
|
|
1963
|
+
connection_time_ms: data.connectionTimeMs ?? null,
|
|
1964
|
+
has_oauth: data.hasOAuth,
|
|
1965
|
+
has_sampling: data.hasSampling,
|
|
1966
|
+
has_elicitation: data.hasElicitation
|
|
1967
|
+
}
|
|
1956
1968
|
});
|
|
1957
|
-
return;
|
|
1958
1969
|
}
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1970
|
+
async trackUseMcpToolCall(data) {
|
|
1971
|
+
if (!this.isEnabled) return;
|
|
1972
|
+
await this.capture({
|
|
1973
|
+
name: "usemcp_tool_call",
|
|
1974
|
+
properties: {
|
|
1975
|
+
tool_name: data.toolName,
|
|
1976
|
+
success: data.success,
|
|
1977
|
+
error_type: data.errorType ?? null,
|
|
1978
|
+
execution_time_ms: data.executionTimeMs ?? null
|
|
1979
|
+
}
|
|
1980
|
+
});
|
|
1966
1981
|
}
|
|
1967
|
-
|
|
1968
|
-
|
|
1982
|
+
async trackUseMcpResourceRead(data) {
|
|
1983
|
+
if (!this.isEnabled) return;
|
|
1984
|
+
await this.capture({
|
|
1985
|
+
name: "usemcp_resource_read",
|
|
1986
|
+
properties: {
|
|
1987
|
+
resource_uri_scheme: data.resourceUri.split(":")[0],
|
|
1988
|
+
success: data.success,
|
|
1989
|
+
error_type: data.errorType ?? null
|
|
1990
|
+
}
|
|
1969
1991
|
});
|
|
1970
|
-
return;
|
|
1971
1992
|
}
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1993
|
+
identify(userId, properties) {
|
|
1994
|
+
this._currUserId = userId;
|
|
1995
|
+
this._storage?.setUserId(userId);
|
|
1996
|
+
if (this._telemetryEnabled) {
|
|
1997
|
+
void capturePostHog({
|
|
1998
|
+
host: HOST,
|
|
1999
|
+
apiKey: PROJECT_API_KEY,
|
|
2000
|
+
event: "$identify",
|
|
2001
|
+
distinctId: userId,
|
|
2002
|
+
properties: { $set: properties ?? {} }
|
|
2003
|
+
});
|
|
2004
|
+
}
|
|
1977
2005
|
}
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
2006
|
+
reset() {
|
|
2007
|
+
this._currUserId = null;
|
|
2008
|
+
}
|
|
2009
|
+
flush() {
|
|
2010
|
+
void Promise.allSettled([...this._pending]);
|
|
2011
|
+
}
|
|
2012
|
+
async shutdown() {
|
|
1981
2013
|
try {
|
|
1982
|
-
|
|
1983
|
-
|
|
2014
|
+
await Promise.allSettled([...this._pending]);
|
|
2015
|
+
logger.debug("Telemetry fetch captures flushed");
|
|
2016
|
+
} catch (e) {
|
|
2017
|
+
logger.debug(`Error flushing telemetry captures: ${e}`);
|
|
1984
2018
|
}
|
|
1985
2019
|
}
|
|
2020
|
+
};
|
|
2021
|
+
var Tel = Telemetry;
|
|
2022
|
+
function setTelemetrySource(source) {
|
|
2023
|
+
Tel.getInstance().setSource(source);
|
|
2024
|
+
}
|
|
2025
|
+
function setProductVersion(version) {
|
|
2026
|
+
Tel.getInstance().setProductVersion(version);
|
|
2027
|
+
}
|
|
2028
|
+
|
|
2029
|
+
// src/telemetry/telemetry-node.ts
|
|
2030
|
+
function getCacheHome(os, path2) {
|
|
2031
|
+
const envVar = process.env.XDG_CACHE_HOME;
|
|
2032
|
+
if (envVar && path2.isAbsolute(envVar)) {
|
|
2033
|
+
return envVar;
|
|
2034
|
+
}
|
|
2035
|
+
const homeDir = os.homedir();
|
|
2036
|
+
if (process.platform === "win32") {
|
|
2037
|
+
const appdata = process.env.LOCALAPPDATA || process.env.APPDATA;
|
|
2038
|
+
if (appdata) return appdata;
|
|
2039
|
+
return path2.join(homeDir, "AppData", "Local");
|
|
2040
|
+
}
|
|
2041
|
+
if (process.platform === "darwin") {
|
|
2042
|
+
return path2.join(homeDir, "Library", "Caches");
|
|
2043
|
+
}
|
|
2044
|
+
return path2.join(homeDir, ".cache");
|
|
2045
|
+
}
|
|
2046
|
+
function createFsStorage() {
|
|
2047
|
+
let fs2;
|
|
2048
|
+
let os;
|
|
2049
|
+
let path2;
|
|
1986
2050
|
try {
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
return;
|
|
1996
|
-
case "cancelled":
|
|
1997
|
-
throw new Error("OAuth authentication was cancelled.");
|
|
1998
|
-
case "timeout":
|
|
1999
|
-
throw new Error(
|
|
2000
|
-
`OAuth callback not received within ${timeoutMs}ms. Ensure /oauth/callback calls onMcpAuthorization().`
|
|
2001
|
-
);
|
|
2002
|
-
case "error":
|
|
2003
|
-
throw new Error(result.error);
|
|
2004
|
-
default:
|
|
2005
|
-
throw new Error("Unexpected OAuth popup result");
|
|
2006
|
-
}
|
|
2007
|
-
} finally {
|
|
2008
|
-
provider.markFlowComplete?.();
|
|
2051
|
+
fs2 = __require("fs");
|
|
2052
|
+
os = __require("os");
|
|
2053
|
+
path2 = __require("path");
|
|
2054
|
+
} catch {
|
|
2055
|
+
return {
|
|
2056
|
+
getUserId: () => null,
|
|
2057
|
+
setUserId: () => void 0
|
|
2058
|
+
};
|
|
2009
2059
|
}
|
|
2060
|
+
const cacheHome = getCacheHome(os, path2);
|
|
2061
|
+
const userIdPath = path2.join(cacheHome, "mcp_use_3", "telemetry_user_id");
|
|
2062
|
+
return {
|
|
2063
|
+
getUserId() {
|
|
2064
|
+
try {
|
|
2065
|
+
if (!fs2.existsSync(userIdPath)) return null;
|
|
2066
|
+
return fs2.readFileSync(userIdPath, "utf-8").trim() || null;
|
|
2067
|
+
} catch {
|
|
2068
|
+
return null;
|
|
2069
|
+
}
|
|
2070
|
+
},
|
|
2071
|
+
setUserId(id) {
|
|
2072
|
+
try {
|
|
2073
|
+
fs2.mkdirSync(path2.dirname(userIdPath), { recursive: true });
|
|
2074
|
+
fs2.writeFileSync(userIdPath, id);
|
|
2075
|
+
} catch {
|
|
2076
|
+
}
|
|
2077
|
+
}
|
|
2078
|
+
};
|
|
2010
2079
|
}
|
|
2080
|
+
configureTelemetryStorage(createFsStorage());
|
|
2081
|
+
|
|
2082
|
+
// src/telemetry/configure-node.ts
|
|
2083
|
+
setClientTelemetryTracker({
|
|
2084
|
+
addServer: (name, config) => Telemetry.getInstance().trackClientAddServer(name, config).catch(() => void 0),
|
|
2085
|
+
removeServer: (name) => Telemetry.getInstance().trackClientRemoveServer(name).catch(() => void 0)
|
|
2086
|
+
});
|
|
2087
|
+
setConnectorTelemetryTracker(
|
|
2088
|
+
(data) => Telemetry.getInstance().trackConnectorInit(data).catch(() => void 0)
|
|
2089
|
+
);
|
|
2090
|
+
|
|
2091
|
+
// src/index.ts
|
|
2092
|
+
init_flow();
|
|
2093
|
+
import { auth as auth2, UnauthorizedError as UnauthorizedError3 } from "@modelcontextprotocol/client";
|
|
2011
2094
|
|
|
2012
2095
|
// src/auth/node.ts
|
|
2013
2096
|
import { createServer as createNetServer } from "net";
|
|
@@ -2840,16 +2923,19 @@ async function createOAuthProvider(serverUrl, options = {}) {
|
|
|
2840
2923
|
}
|
|
2841
2924
|
|
|
2842
2925
|
// src/transport/http.ts
|
|
2926
|
+
init_flow();
|
|
2843
2927
|
init_json_schema_validator();
|
|
2844
2928
|
init_logging();
|
|
2845
2929
|
init_base();
|
|
2846
2930
|
import {
|
|
2847
2931
|
Client,
|
|
2932
|
+
discoverOAuthProtectedResourceMetadata,
|
|
2848
2933
|
SdkError,
|
|
2849
2934
|
SdkHttpError,
|
|
2850
2935
|
StreamableHTTPClientTransport,
|
|
2851
2936
|
UnauthorizedError as UnauthorizedError2
|
|
2852
2937
|
} from "@modelcontextprotocol/client";
|
|
2938
|
+
var MIXED_AUTH_DISCOVERY_TIMEOUT_MS = 2e3;
|
|
2853
2939
|
function detectUnauthorized(err, depth = 0) {
|
|
2854
2940
|
if (!err || depth > 5) return false;
|
|
2855
2941
|
if (err instanceof UnauthorizedError2) return true;
|
|
@@ -2863,6 +2949,11 @@ function detectUnauthorized(err, depth = 0) {
|
|
|
2863
2949
|
}
|
|
2864
2950
|
return false;
|
|
2865
2951
|
}
|
|
2952
|
+
function isOAuthClientProvider(provider) {
|
|
2953
|
+
return Boolean(
|
|
2954
|
+
provider && "redirectToAuthorization" in provider && typeof provider.redirectToAuthorization === "function" && "tokens" in provider && typeof provider.tokens === "function"
|
|
2955
|
+
);
|
|
2956
|
+
}
|
|
2866
2957
|
function createMcpProxyFetch(logicalServerUrl, proxyUrl, baseFetch, serverId) {
|
|
2867
2958
|
const logical = new URL(logicalServerUrl);
|
|
2868
2959
|
const proxy = proxyUrl.replace(/\/$/, "");
|
|
@@ -2888,6 +2979,31 @@ function createMcpProxyFetch(logicalServerUrl, proxyUrl, baseFetch, serverId) {
|
|
|
2888
2979
|
);
|
|
2889
2980
|
};
|
|
2890
2981
|
}
|
|
2982
|
+
function createDeadlineFetch(baseFetch, deadlineSignal) {
|
|
2983
|
+
return async (input, init) => {
|
|
2984
|
+
const requestSignal = init?.signal;
|
|
2985
|
+
if (!requestSignal) {
|
|
2986
|
+
return baseFetch(input, { ...init, signal: deadlineSignal });
|
|
2987
|
+
}
|
|
2988
|
+
const controller = new AbortController();
|
|
2989
|
+
const abortFromRequest = () => controller.abort(requestSignal.reason);
|
|
2990
|
+
const abortFromDeadline = () => controller.abort(deadlineSignal.reason);
|
|
2991
|
+
if (requestSignal.aborted) abortFromRequest();
|
|
2992
|
+
else
|
|
2993
|
+
requestSignal.addEventListener("abort", abortFromRequest, { once: true });
|
|
2994
|
+
if (deadlineSignal.aborted) abortFromDeadline();
|
|
2995
|
+
else
|
|
2996
|
+
deadlineSignal.addEventListener("abort", abortFromDeadline, {
|
|
2997
|
+
once: true
|
|
2998
|
+
});
|
|
2999
|
+
try {
|
|
3000
|
+
return await baseFetch(input, { ...init, signal: controller.signal });
|
|
3001
|
+
} finally {
|
|
3002
|
+
requestSignal.removeEventListener("abort", abortFromRequest);
|
|
3003
|
+
deadlineSignal.removeEventListener("abort", abortFromDeadline);
|
|
3004
|
+
}
|
|
3005
|
+
};
|
|
3006
|
+
}
|
|
2891
3007
|
var HttpConnector = class extends BaseConnector {
|
|
2892
3008
|
baseUrl;
|
|
2893
3009
|
headers;
|
|
@@ -2898,8 +3014,12 @@ var HttpConnector = class extends BaseConnector {
|
|
|
2898
3014
|
gatewayUrl;
|
|
2899
3015
|
serverId;
|
|
2900
3016
|
reconnectionOptions;
|
|
3017
|
+
detectMixedAuth;
|
|
2901
3018
|
transportType = null;
|
|
2902
3019
|
streamableTransport = null;
|
|
3020
|
+
hadAccessTokenAtConnect = false;
|
|
3021
|
+
pendingOAuthCompletion = null;
|
|
3022
|
+
authorizationDiscovery = null;
|
|
2903
3023
|
/**
|
|
2904
3024
|
* Creates an HTTP connector.
|
|
2905
3025
|
*
|
|
@@ -2930,6 +3050,103 @@ var HttpConnector = class extends BaseConnector {
|
|
|
2930
3050
|
};
|
|
2931
3051
|
this.protocolNegotiation = opts.protocolNegotiation ?? "auto";
|
|
2932
3052
|
this.reconnectionOptions = opts.reconnectionOptions;
|
|
3053
|
+
this.detectMixedAuth = opts.detectMixedAuth ?? true;
|
|
3054
|
+
}
|
|
3055
|
+
get oauthProvider() {
|
|
3056
|
+
return isOAuthClientProvider(this.opts.authProvider) ? this.opts.authProvider : void 0;
|
|
3057
|
+
}
|
|
3058
|
+
async completeInteractiveAuthorization() {
|
|
3059
|
+
const provider = this.oauthProvider;
|
|
3060
|
+
if (!provider) {
|
|
3061
|
+
throw new Error("No OAuth client provider is configured");
|
|
3062
|
+
}
|
|
3063
|
+
if (!this.pendingOAuthCompletion) {
|
|
3064
|
+
this.pendingOAuthCompletion = completeOAuthFlow(provider, this.baseUrl, {
|
|
3065
|
+
fetchFn: this.customFetch,
|
|
3066
|
+
finishAuthorization: async (code, iss) => {
|
|
3067
|
+
const transport = this.streamableTransport;
|
|
3068
|
+
if (!transport) {
|
|
3069
|
+
throw new Error("OAuth transport is no longer connected");
|
|
3070
|
+
}
|
|
3071
|
+
await transport.finishAuth(code, iss);
|
|
3072
|
+
}
|
|
3073
|
+
}).then(() => {
|
|
3074
|
+
if (this.authorizationCache) {
|
|
3075
|
+
this.authorizationCache = {
|
|
3076
|
+
...this.authorizationCache,
|
|
3077
|
+
authenticated: true
|
|
3078
|
+
};
|
|
3079
|
+
}
|
|
3080
|
+
}).finally(() => {
|
|
3081
|
+
this.pendingOAuthCompletion = null;
|
|
3082
|
+
});
|
|
3083
|
+
}
|
|
3084
|
+
await this.pendingOAuthCompletion;
|
|
3085
|
+
}
|
|
3086
|
+
async executeRequest(operation) {
|
|
3087
|
+
try {
|
|
3088
|
+
return await operation();
|
|
3089
|
+
} catch (error) {
|
|
3090
|
+
const provider = this.oauthProvider;
|
|
3091
|
+
if (!provider || provider.preventAutoAuth === true || !isOAuthInteractionRequired(error)) {
|
|
3092
|
+
throw error;
|
|
3093
|
+
}
|
|
3094
|
+
await this.completeInteractiveAuthorization();
|
|
3095
|
+
return operation();
|
|
3096
|
+
}
|
|
3097
|
+
}
|
|
3098
|
+
/** Authenticate an already-connected server without requiring a 401 first. */
|
|
3099
|
+
async authenticate() {
|
|
3100
|
+
if (!this.connected || !this.streamableTransport) {
|
|
3101
|
+
throw new Error("MCP client is not connected");
|
|
3102
|
+
}
|
|
3103
|
+
await this.completeInteractiveAuthorization();
|
|
3104
|
+
}
|
|
3105
|
+
async discoverAuthorization() {
|
|
3106
|
+
if (!this.detectMixedAuth || !this.oauthProvider || this.hadAccessTokenAtConnect) {
|
|
3107
|
+
return this.authorizationCache;
|
|
3108
|
+
}
|
|
3109
|
+
if (this.authorizationDiscovery) return this.authorizationDiscovery;
|
|
3110
|
+
this.authorizationDiscovery = this.discoverMixedAuthorization();
|
|
3111
|
+
return this.authorizationDiscovery;
|
|
3112
|
+
}
|
|
3113
|
+
async discoverMixedAuthorization() {
|
|
3114
|
+
const controller = new AbortController();
|
|
3115
|
+
let timeout;
|
|
3116
|
+
const discoveryTimeout = new Promise((_, reject) => {
|
|
3117
|
+
timeout = setTimeout(() => {
|
|
3118
|
+
const error = new Error(
|
|
3119
|
+
`Mixed-auth metadata discovery timed out after ${MIXED_AUTH_DISCOVERY_TIMEOUT_MS}ms`
|
|
3120
|
+
);
|
|
3121
|
+
controller.abort(error);
|
|
3122
|
+
reject(error);
|
|
3123
|
+
}, MIXED_AUTH_DISCOVERY_TIMEOUT_MS);
|
|
3124
|
+
});
|
|
3125
|
+
const baseFetch = this.customFetch ?? globalThis.fetch.bind(globalThis);
|
|
3126
|
+
try {
|
|
3127
|
+
const metadata = await Promise.race([
|
|
3128
|
+
discoverOAuthProtectedResourceMetadata(
|
|
3129
|
+
this.baseUrl,
|
|
3130
|
+
{ protocolVersion: this.negotiatedProtocolVersion },
|
|
3131
|
+
createDeadlineFetch(baseFetch, controller.signal)
|
|
3132
|
+
),
|
|
3133
|
+
discoveryTimeout
|
|
3134
|
+
]);
|
|
3135
|
+
this.authorizationCache = {
|
|
3136
|
+
mode: "mixed",
|
|
3137
|
+
authenticated: false,
|
|
3138
|
+
...metadata.resource ? { resource: metadata.resource } : {},
|
|
3139
|
+
...metadata.scopes_supported ? { scopesSupported: [...metadata.scopes_supported] } : {}
|
|
3140
|
+
};
|
|
3141
|
+
logger.info(
|
|
3142
|
+
"OAuth protected-resource metadata found after anonymous connection; server uses mixed auth"
|
|
3143
|
+
);
|
|
3144
|
+
} catch (error) {
|
|
3145
|
+
logger.debug("Mixed-auth metadata was not discovered:", error);
|
|
3146
|
+
} finally {
|
|
3147
|
+
if (timeout) clearTimeout(timeout);
|
|
3148
|
+
}
|
|
3149
|
+
return this.authorizationCache;
|
|
2933
3150
|
}
|
|
2934
3151
|
buildClientOptions() {
|
|
2935
3152
|
return {
|
|
@@ -3036,6 +3253,16 @@ var HttpConnector = class extends BaseConnector {
|
|
|
3036
3253
|
}
|
|
3037
3254
|
const baseUrl = this.baseUrl;
|
|
3038
3255
|
logger.debug(`Connecting to MCP implementation via HTTP: ${baseUrl}`);
|
|
3256
|
+
const oauthProvider = this.oauthProvider;
|
|
3257
|
+
if (oauthProvider) {
|
|
3258
|
+
try {
|
|
3259
|
+
this.hadAccessTokenAtConnect = Boolean(
|
|
3260
|
+
(await oauthProvider.tokens())?.access_token
|
|
3261
|
+
);
|
|
3262
|
+
} catch {
|
|
3263
|
+
this.hadAccessTokenAtConnect = false;
|
|
3264
|
+
}
|
|
3265
|
+
}
|
|
3039
3266
|
try {
|
|
3040
3267
|
await this.connectWithStreamableHttp(baseUrl);
|
|
3041
3268
|
logger.debug("\u2705 Successfully connected via streamable HTTP");
|
|
@@ -3306,6 +3533,7 @@ var HttpConnector = class extends BaseConnector {
|
|
|
3306
3533
|
}
|
|
3307
3534
|
}
|
|
3308
3535
|
await super.cleanupResources();
|
|
3536
|
+
this.authorizationDiscovery = null;
|
|
3309
3537
|
}
|
|
3310
3538
|
};
|
|
3311
3539
|
|
|
@@ -3387,6 +3615,7 @@ function createConnectorFromConfig(serverConfig, connectorOptions) {
|
|
|
3387
3615
|
fetch: serverConfig.fetch,
|
|
3388
3616
|
authToken: serverConfig.authToken,
|
|
3389
3617
|
authProvider: serverConfig.authProvider,
|
|
3618
|
+
detectMixedAuth: serverConfig.detectMixedAuth,
|
|
3390
3619
|
protocolNegotiation: serverConfig.protocolNegotiation,
|
|
3391
3620
|
timeout: serverConfig.timeout,
|
|
3392
3621
|
roots: serverConfig.roots,
|
|
@@ -3404,6 +3633,7 @@ import fs from "fs";
|
|
|
3404
3633
|
import path from "path";
|
|
3405
3634
|
|
|
3406
3635
|
// src/core/base.ts
|
|
3636
|
+
init_flow();
|
|
3407
3637
|
init_logging();
|
|
3408
3638
|
|
|
3409
3639
|
// src/core/skills.ts
|
|
@@ -3636,6 +3866,18 @@ var MCPConnection = class {
|
|
|
3636
3866
|
get serverInfo() {
|
|
3637
3867
|
return this.connector.serverInfo;
|
|
3638
3868
|
}
|
|
3869
|
+
/** OAuth state discovered for this connection, when available. */
|
|
3870
|
+
get authorization() {
|
|
3871
|
+
return this.connector.authorization;
|
|
3872
|
+
}
|
|
3873
|
+
/** Discover optional OAuth metadata without delaying MCP readiness. */
|
|
3874
|
+
async discoverAuthorization() {
|
|
3875
|
+
return this.connector.discoverAuthorization();
|
|
3876
|
+
}
|
|
3877
|
+
/** Authenticate an already-connected mixed-auth server. */
|
|
3878
|
+
async authenticate() {
|
|
3879
|
+
await this.connector.authenticate();
|
|
3880
|
+
}
|
|
3639
3881
|
/**
|
|
3640
3882
|
* The negotiated protocol era for this session's connection:
|
|
3641
3883
|
* `"legacy"` (2025-era) or `"modern"` (2026-07-28-era).
|
|
@@ -3668,7 +3910,8 @@ var MCPConnection = class {
|
|
|
3668
3910
|
...server ? { server } : {},
|
|
3669
3911
|
capabilities,
|
|
3670
3912
|
instructions: this.connector.instructions,
|
|
3671
|
-
extensions
|
|
3913
|
+
extensions,
|
|
3914
|
+
...this.authorization ? { authorization: this.authorization } : {}
|
|
3672
3915
|
};
|
|
3673
3916
|
}
|
|
3674
3917
|
/**
|
|
@@ -3899,7 +4142,7 @@ var MCPConnection = class {
|
|
|
3899
4142
|
};
|
|
3900
4143
|
|
|
3901
4144
|
// src/core/base.ts
|
|
3902
|
-
function
|
|
4145
|
+
function isOAuthClientProvider2(provider) {
|
|
3903
4146
|
return !!provider && typeof provider === "object" && "redirectUrl" in provider && "clientMetadata" in provider;
|
|
3904
4147
|
}
|
|
3905
4148
|
var BaseMCPClient = class {
|
|
@@ -4132,7 +4375,7 @@ var BaseMCPClient = class {
|
|
|
4132
4375
|
...serverConfig,
|
|
4133
4376
|
authProvider: oauthProvider
|
|
4134
4377
|
};
|
|
4135
|
-
} else if ("authProvider" in serverConfig && serverConfig.authProvider &&
|
|
4378
|
+
} else if ("authProvider" in serverConfig && serverConfig.authProvider && isOAuthClientProvider2(serverConfig.authProvider)) {
|
|
4136
4379
|
oauthProvider = serverConfig.authProvider;
|
|
4137
4380
|
}
|
|
4138
4381
|
const openSession = async () => {
|
|
@@ -5818,6 +6061,7 @@ export {
|
|
|
5818
6061
|
createOAuthProvider,
|
|
5819
6062
|
decline,
|
|
5820
6063
|
getDefaults,
|
|
6064
|
+
isOAuthInteractionRequired,
|
|
5821
6065
|
isUnauthorized,
|
|
5822
6066
|
isVMAvailable,
|
|
5823
6067
|
loadConfigFile,
|