@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.
@@ -270,6 +270,7 @@ var PERSISTED_SERVER_CONFIG_KEYS = [
270
270
  "reconnectionOptions",
271
271
  "popupFeatures",
272
272
  "preventAutoAuth",
273
+ "detectMixedAuth",
273
274
  "useRedirectFlow",
274
275
  "protocolNegotiation",
275
276
  "timeout",
@@ -449,11 +450,136 @@ import { useCallback as useCallback2, useEffect, useMemo, useRef, useState } fro
449
450
  // src/transport/http.ts
450
451
  import {
451
452
  Client,
453
+ discoverOAuthProtectedResourceMetadata,
452
454
  SdkError,
453
455
  SdkHttpError,
454
456
  StreamableHTTPClientTransport,
457
+ UnauthorizedError as UnauthorizedError2
458
+ } from "@modelcontextprotocol/client";
459
+
460
+ // src/auth/flow.ts
461
+ import {
462
+ auth,
463
+ InsufficientScopeError,
455
464
  UnauthorizedError
456
465
  } from "@modelcontextprotocol/client";
466
+ var DEFAULT_AUTH_TIMEOUT_MS = 5 * 6e4;
467
+ function isUnauthorized(err, depth = 0) {
468
+ if (!err || depth > 5) return false;
469
+ if (err instanceof UnauthorizedError) return true;
470
+ if (err instanceof Error) {
471
+ const code = err.code;
472
+ if (code === 401) return true;
473
+ if (err.name === "UnauthorizedError") return true;
474
+ const message = err.message ?? "";
475
+ if (message.includes("401") || message.includes("Unauthorized")) {
476
+ return true;
477
+ }
478
+ if (err.cause && isUnauthorized(err.cause, depth + 1)) return true;
479
+ const data = err.data;
480
+ if (data?.cause && isUnauthorized(data.cause, depth + 1)) return true;
481
+ }
482
+ return false;
483
+ }
484
+ function isOAuthInteractionRequired(err, depth = 0) {
485
+ if (!err || depth > 5) return false;
486
+ if (err instanceof InsufficientScopeError || err instanceof UnauthorizedError) {
487
+ return true;
488
+ }
489
+ if (err instanceof Error) {
490
+ if (err.name === "InsufficientScopeError" || err.name === "UnauthorizedError") {
491
+ return true;
492
+ }
493
+ if (err.cause && isOAuthInteractionRequired(err.cause, depth + 1)) {
494
+ return true;
495
+ }
496
+ const data = err.data;
497
+ if (data?.cause && isOAuthInteractionRequired(data.cause, depth + 1)) {
498
+ return true;
499
+ }
500
+ }
501
+ return false;
502
+ }
503
+ async function completeOAuthFlow(provider, serverUrl, options = {}) {
504
+ const flowProvider = provider;
505
+ const timeoutMs = options.timeoutMs ?? DEFAULT_AUTH_TIMEOUT_MS;
506
+ const fetchFn = options.fetchFn ?? flowProvider.getProxyFetch?.() ?? void 0;
507
+ if (!flowProvider.hasPendingFlow) {
508
+ const result = await auth(provider, { serverUrl, fetchFn });
509
+ if (result === "AUTHORIZED") return;
510
+ if (result !== "REDIRECT") {
511
+ throw new Error(`Unexpected OAuth auth() result: ${result}`);
512
+ }
513
+ }
514
+ if (flowProvider.preventAutoAuth === true && typeof flowProvider.startAuthorization === "function") {
515
+ flowProvider.startAuthorization();
516
+ }
517
+ if (typeof flowProvider.getAuthorizationResponse === "function" || typeof flowProvider.getAuthorizationCode === "function") {
518
+ const response = typeof flowProvider.getAuthorizationResponse === "function" ? await flowProvider.getAuthorizationResponse() : { code: await flowProvider.getAuthorizationCode() };
519
+ if (options.finishAuthorization) {
520
+ await options.finishAuthorization(response.code, response.iss);
521
+ } else {
522
+ await auth(provider, {
523
+ serverUrl,
524
+ authorizationCode: response.code,
525
+ ...response.iss !== void 0 ? { iss: response.iss } : {},
526
+ fetchFn
527
+ });
528
+ }
529
+ return;
530
+ }
531
+ await waitForBrowserAuthComplete(flowProvider, timeoutMs);
532
+ }
533
+ async function waitForBrowserAuthComplete(provider, timeoutMs) {
534
+ if (typeof window === "undefined") {
535
+ throw new Error(
536
+ "OAuth redirect requires a browser environment or a provider with getAuthorizationCode()"
537
+ );
538
+ }
539
+ if (provider.useRedirectFlow) {
540
+ await new Promise(() => {
541
+ });
542
+ return;
543
+ }
544
+ const tokensKey = provider.getKey?.("tokens");
545
+ if (!tokensKey) {
546
+ throw new Error(
547
+ "Browser OAuth provider must expose getKey() for token storage"
548
+ );
549
+ }
550
+ let state = null;
551
+ const authUrl = provider.getLastAttemptedAuthUrl?.();
552
+ if (authUrl) {
553
+ try {
554
+ state = new URL(authUrl).searchParams.get("state");
555
+ } catch {
556
+ }
557
+ }
558
+ try {
559
+ const result = await runAuthPopup({
560
+ popup: null,
561
+ state,
562
+ tokensKey,
563
+ timeoutMs
564
+ });
565
+ switch (result.kind) {
566
+ case "success":
567
+ return;
568
+ case "cancelled":
569
+ throw new Error("OAuth authentication was cancelled.");
570
+ case "timeout":
571
+ throw new Error(
572
+ `OAuth callback not received within ${timeoutMs}ms. Ensure /oauth/callback calls onMcpAuthorization().`
573
+ );
574
+ case "error":
575
+ throw new Error(result.error);
576
+ default:
577
+ throw new Error("Unexpected OAuth popup result");
578
+ }
579
+ } finally {
580
+ provider.markFlowComplete?.();
581
+ }
582
+ }
457
583
 
458
584
  // src/utils/json-schema-validator.ts
459
585
  import {
@@ -517,6 +643,7 @@ var BaseConnector = class {
517
643
  toolsCache = null;
518
644
  capabilitiesCache = null;
519
645
  serverInfoCache = null;
646
+ authorizationCache;
520
647
  connected = false;
521
648
  opts;
522
649
  notificationHandlers = [];
@@ -780,6 +907,28 @@ var BaseConnector = class {
780
907
  "setupElicitationHandler: Elicitation handler registered successfully"
781
908
  );
782
909
  }
910
+ /**
911
+ * Run one logical MCP operation. HTTP connectors override this host seam to
912
+ * finish an SDK-started interactive OAuth flow and retry exactly once.
913
+ */
914
+ async executeRequest(operation) {
915
+ return operation();
916
+ }
917
+ /** OAuth state discovered for the active connection, when available. */
918
+ get authorization() {
919
+ return this.authorizationCache;
920
+ }
921
+ /**
922
+ * Discover optional authorization metadata without delaying connection
923
+ * readiness. HTTP connectors override this with RFC 9728 discovery.
924
+ */
925
+ async discoverAuthorization() {
926
+ return this.authorization;
927
+ }
928
+ /** Start optional OAuth for a connected mixed-auth server. */
929
+ async authenticate() {
930
+ throw new Error("This connector does not support interactive OAuth");
931
+ }
783
932
  /**
784
933
  * Disconnects the SDK client and releases transport resources.
785
934
  *
@@ -827,13 +976,13 @@ var BaseConnector = class {
827
976
  icons: serverInfo.icons
828
977
  } : null;
829
978
  try {
830
- const listToolsRes = await this.client.listTools(
831
- void 0,
832
- defaultRequestOptions
979
+ const listToolsRes = await this.executeRequest(
980
+ () => this.client.listTools(void 0, defaultRequestOptions)
833
981
  );
834
982
  this.toolsCache = listToolsRes.tools ?? [];
835
983
  logger.debug(`Fetched ${this.toolsCache.length} tools from server`);
836
984
  } catch (err) {
985
+ if (isOAuthInteractionRequired(err)) throw err;
837
986
  const error = err;
838
987
  if (error.code === -32601) {
839
988
  logger.debug("Server does not implement tools/list, assuming no tools");
@@ -907,9 +1056,8 @@ var BaseConnector = class {
907
1056
  const progressHandler = enhancedOptions?.onprogress;
908
1057
  if (progressHandler) this.activeProgressHandlers.add(progressHandler);
909
1058
  try {
910
- const res = await this.client.callTool(
911
- { name, arguments: args },
912
- enhancedOptions
1059
+ const res = await this.executeRequest(
1060
+ () => this.client.callTool({ name, arguments: args }, enhancedOptions)
913
1061
  );
914
1062
  logger.debug(`Tool '${name}' returned`, res);
915
1063
  return res;
@@ -929,7 +1077,9 @@ var BaseConnector = class {
929
1077
  throw new Error("MCP client is not connected");
930
1078
  }
931
1079
  logger.debug("[listTools] Fetching fresh tools from server...");
932
- const result = await this.client.listTools(void 0, options);
1080
+ const result = await this.executeRequest(
1081
+ () => this.client.listTools(void 0, options)
1082
+ );
933
1083
  const tools = result.tools ? [...result.tools] : [];
934
1084
  logger.debug(
935
1085
  `[listTools] Returned ${tools.length} tools:`,
@@ -949,7 +1099,9 @@ var BaseConnector = class {
949
1099
  throw new Error("MCP client is not connected");
950
1100
  }
951
1101
  logger.debug("Listing resources", cursor ? `with cursor: ${cursor}` : "");
952
- return await this.client.listResources({ cursor }, options);
1102
+ return await this.executeRequest(
1103
+ () => this.client.listResources({ cursor }, options)
1104
+ );
953
1105
  }
954
1106
  /**
955
1107
  * List all resources from the server, automatically handling pagination
@@ -967,14 +1119,16 @@ var BaseConnector = class {
967
1119
  }
968
1120
  try {
969
1121
  logger.debug("Listing all resources (with auto-pagination)");
970
- const allResources = [];
971
- let cursor = void 0;
972
- do {
973
- const result = await this.client.listResources({ cursor }, options);
974
- allResources.push(...result.resources || []);
975
- cursor = result.nextCursor;
976
- } while (cursor);
977
- return { resources: allResources };
1122
+ return await this.executeRequest(async () => {
1123
+ const allResources = [];
1124
+ let cursor = void 0;
1125
+ do {
1126
+ const result = await this.client.listResources({ cursor }, options);
1127
+ allResources.push(...result.resources || []);
1128
+ cursor = result.nextCursor;
1129
+ } while (cursor);
1130
+ return { resources: allResources };
1131
+ });
978
1132
  } catch (err) {
979
1133
  const error = err;
980
1134
  if (error.code === -32601) {
@@ -995,7 +1149,9 @@ var BaseConnector = class {
995
1149
  throw new Error("MCP client is not connected");
996
1150
  }
997
1151
  logger.debug("Listing resource templates");
998
- return await this.client.listResourceTemplates(void 0, options);
1152
+ return await this.executeRequest(
1153
+ () => this.client.listResourceTemplates(void 0, options)
1154
+ );
999
1155
  }
1000
1156
  /**
1001
1157
  * Request completion suggestions for a prompt or resource template argument
@@ -1009,7 +1165,9 @@ var BaseConnector = class {
1009
1165
  throw new Error("MCP client is not connected");
1010
1166
  }
1011
1167
  logger.debug("[complete] Requesting completions for:", params.ref);
1012
- const result = await this.client.complete(params, options);
1168
+ const result = await this.executeRequest(
1169
+ () => this.client.complete(params, options)
1170
+ );
1013
1171
  logger.debug(
1014
1172
  `[complete] Received ${result.completion.values.length} suggestions`
1015
1173
  );
@@ -1027,7 +1185,9 @@ var BaseConnector = class {
1027
1185
  throw new Error("MCP client is not connected");
1028
1186
  }
1029
1187
  logger.debug(`Reading resource ${uri}`);
1030
- const res = await this.client.readResource({ uri }, options);
1188
+ const res = await this.executeRequest(
1189
+ () => this.client.readResource({ uri }, options)
1190
+ );
1031
1191
  return res;
1032
1192
  }
1033
1193
  /**
@@ -1041,7 +1201,9 @@ var BaseConnector = class {
1041
1201
  throw new Error("MCP client is not connected");
1042
1202
  }
1043
1203
  logger.debug(`Subscribing to resource: ${uri}`);
1044
- return await this.client.subscribeResource({ uri }, options);
1204
+ return await this.executeRequest(
1205
+ () => this.client.subscribeResource({ uri }, options)
1206
+ );
1045
1207
  }
1046
1208
  /**
1047
1209
  * Unsubscribe from resource updates
@@ -1054,7 +1216,9 @@ var BaseConnector = class {
1054
1216
  throw new Error("MCP client is not connected");
1055
1217
  }
1056
1218
  logger.debug(`Unsubscribing from resource: ${uri}`);
1057
- return await this.client.unsubscribeResource({ uri }, options);
1219
+ return await this.executeRequest(
1220
+ () => this.client.unsubscribeResource({ uri }, options)
1221
+ );
1058
1222
  }
1059
1223
  /**
1060
1224
  * Lists prompts exposed by the server.
@@ -1071,7 +1235,7 @@ var BaseConnector = class {
1071
1235
  }
1072
1236
  try {
1073
1237
  logger.debug("Listing prompts");
1074
- return await this.client.listPrompts();
1238
+ return await this.executeRequest(() => this.client.listPrompts());
1075
1239
  } catch (err) {
1076
1240
  const error = err;
1077
1241
  if (error.code === -32601) {
@@ -1093,7 +1257,9 @@ var BaseConnector = class {
1093
1257
  throw new Error("MCP client is not connected");
1094
1258
  }
1095
1259
  logger.debug(`Getting prompt ${name}`);
1096
- return await this.client.getPrompt({ name, arguments: args });
1260
+ return await this.executeRequest(
1261
+ () => this.client.getPrompt({ name, arguments: args })
1262
+ );
1097
1263
  }
1098
1264
  /**
1099
1265
  * Sends a raw, potentially non-standard request through the SDK client.
@@ -1108,10 +1274,12 @@ var BaseConnector = class {
1108
1274
  throw new Error("MCP client is not connected");
1109
1275
  }
1110
1276
  logger.debug(`Sending raw request '${method}' with params`, params);
1111
- return await this.client.request(
1112
- { method, params: params ?? {} },
1113
- passthroughResultSchema,
1114
- options
1277
+ return await this.executeRequest(
1278
+ () => this.client.request(
1279
+ { method, params: params ?? {} },
1280
+ passthroughResultSchema,
1281
+ options
1282
+ )
1115
1283
  );
1116
1284
  }
1117
1285
  /**
@@ -1144,6 +1312,7 @@ var BaseConnector = class {
1144
1312
  }
1145
1313
  }
1146
1314
  this.toolsCache = null;
1315
+ this.authorizationCache = void 0;
1147
1316
  if (issues.length) {
1148
1317
  logger.warn(`Resource cleanup finished with ${issues.length} issue(s)`);
1149
1318
  }
@@ -1151,9 +1320,10 @@ var BaseConnector = class {
1151
1320
  };
1152
1321
 
1153
1322
  // src/transport/http.ts
1323
+ var MIXED_AUTH_DISCOVERY_TIMEOUT_MS = 2e3;
1154
1324
  function detectUnauthorized(err, depth = 0) {
1155
1325
  if (!err || depth > 5) return false;
1156
- if (err instanceof UnauthorizedError) return true;
1326
+ if (err instanceof UnauthorizedError2) return true;
1157
1327
  if (err instanceof SdkHttpError && err.status === 401) return true;
1158
1328
  if (err instanceof Error) {
1159
1329
  if (err.cause) {
@@ -1164,6 +1334,11 @@ function detectUnauthorized(err, depth = 0) {
1164
1334
  }
1165
1335
  return false;
1166
1336
  }
1337
+ function isOAuthClientProvider(provider) {
1338
+ return Boolean(
1339
+ provider && "redirectToAuthorization" in provider && typeof provider.redirectToAuthorization === "function" && "tokens" in provider && typeof provider.tokens === "function"
1340
+ );
1341
+ }
1167
1342
  function createMcpProxyFetch(logicalServerUrl, proxyUrl, baseFetch, serverId) {
1168
1343
  const logical = new URL(logicalServerUrl);
1169
1344
  const proxy = proxyUrl.replace(/\/$/, "");
@@ -1189,6 +1364,31 @@ function createMcpProxyFetch(logicalServerUrl, proxyUrl, baseFetch, serverId) {
1189
1364
  );
1190
1365
  };
1191
1366
  }
1367
+ function createDeadlineFetch(baseFetch, deadlineSignal) {
1368
+ return async (input, init) => {
1369
+ const requestSignal = init?.signal;
1370
+ if (!requestSignal) {
1371
+ return baseFetch(input, { ...init, signal: deadlineSignal });
1372
+ }
1373
+ const controller = new AbortController();
1374
+ const abortFromRequest = () => controller.abort(requestSignal.reason);
1375
+ const abortFromDeadline = () => controller.abort(deadlineSignal.reason);
1376
+ if (requestSignal.aborted) abortFromRequest();
1377
+ else
1378
+ requestSignal.addEventListener("abort", abortFromRequest, { once: true });
1379
+ if (deadlineSignal.aborted) abortFromDeadline();
1380
+ else
1381
+ deadlineSignal.addEventListener("abort", abortFromDeadline, {
1382
+ once: true
1383
+ });
1384
+ try {
1385
+ return await baseFetch(input, { ...init, signal: controller.signal });
1386
+ } finally {
1387
+ requestSignal.removeEventListener("abort", abortFromRequest);
1388
+ deadlineSignal.removeEventListener("abort", abortFromDeadline);
1389
+ }
1390
+ };
1391
+ }
1192
1392
  var HttpConnector = class extends BaseConnector {
1193
1393
  baseUrl;
1194
1394
  headers;
@@ -1199,8 +1399,12 @@ var HttpConnector = class extends BaseConnector {
1199
1399
  gatewayUrl;
1200
1400
  serverId;
1201
1401
  reconnectionOptions;
1402
+ detectMixedAuth;
1202
1403
  transportType = null;
1203
1404
  streamableTransport = null;
1405
+ hadAccessTokenAtConnect = false;
1406
+ pendingOAuthCompletion = null;
1407
+ authorizationDiscovery = null;
1204
1408
  /**
1205
1409
  * Creates an HTTP connector.
1206
1410
  *
@@ -1231,6 +1435,103 @@ var HttpConnector = class extends BaseConnector {
1231
1435
  };
1232
1436
  this.protocolNegotiation = opts.protocolNegotiation ?? "auto";
1233
1437
  this.reconnectionOptions = opts.reconnectionOptions;
1438
+ this.detectMixedAuth = opts.detectMixedAuth ?? true;
1439
+ }
1440
+ get oauthProvider() {
1441
+ return isOAuthClientProvider(this.opts.authProvider) ? this.opts.authProvider : void 0;
1442
+ }
1443
+ async completeInteractiveAuthorization() {
1444
+ const provider = this.oauthProvider;
1445
+ if (!provider) {
1446
+ throw new Error("No OAuth client provider is configured");
1447
+ }
1448
+ if (!this.pendingOAuthCompletion) {
1449
+ this.pendingOAuthCompletion = completeOAuthFlow(provider, this.baseUrl, {
1450
+ fetchFn: this.customFetch,
1451
+ finishAuthorization: async (code, iss) => {
1452
+ const transport = this.streamableTransport;
1453
+ if (!transport) {
1454
+ throw new Error("OAuth transport is no longer connected");
1455
+ }
1456
+ await transport.finishAuth(code, iss);
1457
+ }
1458
+ }).then(() => {
1459
+ if (this.authorizationCache) {
1460
+ this.authorizationCache = {
1461
+ ...this.authorizationCache,
1462
+ authenticated: true
1463
+ };
1464
+ }
1465
+ }).finally(() => {
1466
+ this.pendingOAuthCompletion = null;
1467
+ });
1468
+ }
1469
+ await this.pendingOAuthCompletion;
1470
+ }
1471
+ async executeRequest(operation) {
1472
+ try {
1473
+ return await operation();
1474
+ } catch (error) {
1475
+ const provider = this.oauthProvider;
1476
+ if (!provider || provider.preventAutoAuth === true || !isOAuthInteractionRequired(error)) {
1477
+ throw error;
1478
+ }
1479
+ await this.completeInteractiveAuthorization();
1480
+ return operation();
1481
+ }
1482
+ }
1483
+ /** Authenticate an already-connected server without requiring a 401 first. */
1484
+ async authenticate() {
1485
+ if (!this.connected || !this.streamableTransport) {
1486
+ throw new Error("MCP client is not connected");
1487
+ }
1488
+ await this.completeInteractiveAuthorization();
1489
+ }
1490
+ async discoverAuthorization() {
1491
+ if (!this.detectMixedAuth || !this.oauthProvider || this.hadAccessTokenAtConnect) {
1492
+ return this.authorizationCache;
1493
+ }
1494
+ if (this.authorizationDiscovery) return this.authorizationDiscovery;
1495
+ this.authorizationDiscovery = this.discoverMixedAuthorization();
1496
+ return this.authorizationDiscovery;
1497
+ }
1498
+ async discoverMixedAuthorization() {
1499
+ const controller = new AbortController();
1500
+ let timeout;
1501
+ const discoveryTimeout = new Promise((_, reject) => {
1502
+ timeout = setTimeout(() => {
1503
+ const error = new Error(
1504
+ `Mixed-auth metadata discovery timed out after ${MIXED_AUTH_DISCOVERY_TIMEOUT_MS}ms`
1505
+ );
1506
+ controller.abort(error);
1507
+ reject(error);
1508
+ }, MIXED_AUTH_DISCOVERY_TIMEOUT_MS);
1509
+ });
1510
+ const baseFetch = this.customFetch ?? globalThis.fetch.bind(globalThis);
1511
+ try {
1512
+ const metadata = await Promise.race([
1513
+ discoverOAuthProtectedResourceMetadata(
1514
+ this.baseUrl,
1515
+ { protocolVersion: this.negotiatedProtocolVersion },
1516
+ createDeadlineFetch(baseFetch, controller.signal)
1517
+ ),
1518
+ discoveryTimeout
1519
+ ]);
1520
+ this.authorizationCache = {
1521
+ mode: "mixed",
1522
+ authenticated: false,
1523
+ ...metadata.resource ? { resource: metadata.resource } : {},
1524
+ ...metadata.scopes_supported ? { scopesSupported: [...metadata.scopes_supported] } : {}
1525
+ };
1526
+ logger.info(
1527
+ "OAuth protected-resource metadata found after anonymous connection; server uses mixed auth"
1528
+ );
1529
+ } catch (error) {
1530
+ logger.debug("Mixed-auth metadata was not discovered:", error);
1531
+ } finally {
1532
+ if (timeout) clearTimeout(timeout);
1533
+ }
1534
+ return this.authorizationCache;
1234
1535
  }
1235
1536
  buildClientOptions() {
1236
1537
  return {
@@ -1337,6 +1638,16 @@ var HttpConnector = class extends BaseConnector {
1337
1638
  }
1338
1639
  const baseUrl = this.baseUrl;
1339
1640
  logger.debug(`Connecting to MCP implementation via HTTP: ${baseUrl}`);
1641
+ const oauthProvider = this.oauthProvider;
1642
+ if (oauthProvider) {
1643
+ try {
1644
+ this.hadAccessTokenAtConnect = Boolean(
1645
+ (await oauthProvider.tokens())?.access_token
1646
+ );
1647
+ } catch {
1648
+ this.hadAccessTokenAtConnect = false;
1649
+ }
1650
+ }
1340
1651
  try {
1341
1652
  await this.connectWithStreamableHttp(baseUrl);
1342
1653
  logger.debug("\u2705 Successfully connected via streamable HTTP");
@@ -1607,11 +1918,12 @@ var HttpConnector = class extends BaseConnector {
1607
1918
  }
1608
1919
  }
1609
1920
  await super.cleanupResources();
1921
+ this.authorizationDiscovery = null;
1610
1922
  }
1611
1923
  };
1612
1924
 
1613
1925
  // src/utils/version.ts
1614
- var VERSION = "2.1.0";
1926
+ var VERSION = "2.1.1-canary.1";
1615
1927
  function getPackageVersion() {
1616
1928
  return VERSION;
1617
1929
  }
@@ -2577,29 +2889,43 @@ var BrowserOAuthClientProvider = class {
2577
2889
  * @param authorizationUrl - The fully constructed authorization URL from the SDK.
2578
2890
  */
2579
2891
  async redirectToAuthorization(authorizationUrl) {
2580
- const sanitizedAuthUrl = await this.prepareAuthorizationUrl(authorizationUrl);
2892
+ await this.prepareAuthorizationUrl(authorizationUrl);
2581
2893
  if (this.preventAutoAuth) {
2582
2894
  console.info(
2583
2895
  `[${this.storageKeyPrefix}] Auto-auth prevented. Authorization URL stored for manual trigger.`
2584
2896
  );
2585
2897
  return;
2586
2898
  }
2899
+ this.startAuthorization();
2900
+ }
2901
+ /**
2902
+ * Open the authorization URL prepared by the official SDK.
2903
+ *
2904
+ * This is the explicit-user-action counterpart to `preventAutoAuth`: the
2905
+ * provider still lets the SDK own discovery and PKCE state, while a host can
2906
+ * launch the stored authorization request later from an Authenticate button.
2907
+ */
2908
+ startAuthorization() {
2909
+ const authorizationUrl = this.lastAttemptedAuthUrl;
2910
+ if (!authorizationUrl) {
2911
+ throw new Error("No prepared OAuth authorization is available");
2912
+ }
2587
2913
  if (this.useRedirectFlow) {
2588
2914
  console.info(
2589
2915
  `[${this.storageKeyPrefix}] Redirecting to authorization URL (full-page redirect).`
2590
2916
  );
2591
- window.location.href = sanitizedAuthUrl;
2917
+ window.location.href = authorizationUrl;
2592
2918
  return;
2593
2919
  }
2594
2920
  const popupFeatures = "width=600,height=700,resizable=yes,scrollbars=yes,status=yes";
2595
2921
  try {
2596
2922
  const popup = window.open(
2597
- sanitizedAuthUrl,
2923
+ authorizationUrl,
2598
2924
  `mcp_auth_${this.serverUrlHash}`,
2599
2925
  popupFeatures
2600
2926
  );
2601
2927
  if (this.onPopupWindow) {
2602
- this.onPopupWindow(sanitizedAuthUrl, popupFeatures, popup);
2928
+ this.onPopupWindow(authorizationUrl, popupFeatures, popup);
2603
2929
  }
2604
2930
  if (!popup || popup.closed || typeof popup.closed === "undefined") {
2605
2931
  console.warn(
@@ -3148,103 +3474,6 @@ function setTelemetrySource(source) {
3148
3474
  Tel.getInstance().setSource(source);
3149
3475
  }
3150
3476
 
3151
- // src/auth/flow.ts
3152
- import {
3153
- auth,
3154
- UnauthorizedError as UnauthorizedError2
3155
- } from "@modelcontextprotocol/client";
3156
- var DEFAULT_AUTH_TIMEOUT_MS = 5 * 6e4;
3157
- function isUnauthorized(err, depth = 0) {
3158
- if (!err || depth > 5) return false;
3159
- if (err instanceof UnauthorizedError2) return true;
3160
- if (err instanceof Error) {
3161
- const code = err.code;
3162
- if (code === 401) return true;
3163
- if (err.name === "UnauthorizedError") return true;
3164
- const message = err.message ?? "";
3165
- if (message.includes("401") || message.includes("Unauthorized")) {
3166
- return true;
3167
- }
3168
- if (err.cause && isUnauthorized(err.cause, depth + 1)) return true;
3169
- const data = err.data;
3170
- if (data?.cause && isUnauthorized(data.cause, depth + 1)) return true;
3171
- }
3172
- return false;
3173
- }
3174
- async function completeOAuthFlow(provider, serverUrl, options = {}) {
3175
- const flowProvider = provider;
3176
- const timeoutMs = options.timeoutMs ?? DEFAULT_AUTH_TIMEOUT_MS;
3177
- const fetchFn = options.fetchFn ?? flowProvider.getProxyFetch?.() ?? void 0;
3178
- if (!flowProvider.hasPendingFlow) {
3179
- const result = await auth(provider, { serverUrl, fetchFn });
3180
- if (result === "AUTHORIZED") return;
3181
- if (result !== "REDIRECT") {
3182
- throw new Error(`Unexpected OAuth auth() result: ${result}`);
3183
- }
3184
- }
3185
- if (typeof flowProvider.getAuthorizationResponse === "function" || typeof flowProvider.getAuthorizationCode === "function") {
3186
- const response = typeof flowProvider.getAuthorizationResponse === "function" ? await flowProvider.getAuthorizationResponse() : { code: await flowProvider.getAuthorizationCode() };
3187
- await auth(provider, {
3188
- serverUrl,
3189
- authorizationCode: response.code,
3190
- ...response.iss !== void 0 ? { iss: response.iss } : {},
3191
- fetchFn
3192
- });
3193
- return;
3194
- }
3195
- await waitForBrowserAuthComplete(flowProvider, timeoutMs);
3196
- }
3197
- async function waitForBrowserAuthComplete(provider, timeoutMs) {
3198
- if (typeof window === "undefined") {
3199
- throw new Error(
3200
- "OAuth redirect requires a browser environment or a provider with getAuthorizationCode()"
3201
- );
3202
- }
3203
- if (provider.useRedirectFlow) {
3204
- await new Promise(() => {
3205
- });
3206
- return;
3207
- }
3208
- const tokensKey = provider.getKey?.("tokens");
3209
- if (!tokensKey) {
3210
- throw new Error(
3211
- "Browser OAuth provider must expose getKey() for token storage"
3212
- );
3213
- }
3214
- let state = null;
3215
- const authUrl = provider.getLastAttemptedAuthUrl?.();
3216
- if (authUrl) {
3217
- try {
3218
- state = new URL(authUrl).searchParams.get("state");
3219
- } catch {
3220
- }
3221
- }
3222
- try {
3223
- const result = await runAuthPopup({
3224
- popup: null,
3225
- state,
3226
- tokensKey,
3227
- timeoutMs
3228
- });
3229
- switch (result.kind) {
3230
- case "success":
3231
- return;
3232
- case "cancelled":
3233
- throw new Error("OAuth authentication was cancelled.");
3234
- case "timeout":
3235
- throw new Error(
3236
- `OAuth callback not received within ${timeoutMs}ms. Ensure /oauth/callback calls onMcpAuthorization().`
3237
- );
3238
- case "error":
3239
- throw new Error(result.error);
3240
- default:
3241
- throw new Error("Unexpected OAuth popup result");
3242
- }
3243
- } finally {
3244
- provider.markFlowComplete?.();
3245
- }
3246
- }
3247
-
3248
3477
  // src/core/base.ts
3249
3478
  init_logging();
3250
3479
 
@@ -3475,6 +3704,18 @@ var MCPConnection = class {
3475
3704
  get serverInfo() {
3476
3705
  return this.connector.serverInfo;
3477
3706
  }
3707
+ /** OAuth state discovered for this connection, when available. */
3708
+ get authorization() {
3709
+ return this.connector.authorization;
3710
+ }
3711
+ /** Discover optional OAuth metadata without delaying MCP readiness. */
3712
+ async discoverAuthorization() {
3713
+ return this.connector.discoverAuthorization();
3714
+ }
3715
+ /** Authenticate an already-connected mixed-auth server. */
3716
+ async authenticate() {
3717
+ await this.connector.authenticate();
3718
+ }
3478
3719
  /**
3479
3720
  * The negotiated protocol era for this session's connection:
3480
3721
  * `"legacy"` (2025-era) or `"modern"` (2026-07-28-era).
@@ -3507,7 +3748,8 @@ var MCPConnection = class {
3507
3748
  ...server ? { server } : {},
3508
3749
  capabilities,
3509
3750
  instructions: this.connector.instructions,
3510
- extensions
3751
+ extensions,
3752
+ ...this.authorization ? { authorization: this.authorization } : {}
3511
3753
  };
3512
3754
  }
3513
3755
  /**
@@ -3747,7 +3989,7 @@ function trackClientRemoveServer(name) {
3747
3989
  }
3748
3990
 
3749
3991
  // src/core/base.ts
3750
- function isOAuthClientProvider(provider) {
3992
+ function isOAuthClientProvider2(provider) {
3751
3993
  return !!provider && typeof provider === "object" && "redirectUrl" in provider && "clientMetadata" in provider;
3752
3994
  }
3753
3995
  var BaseMCPClient = class {
@@ -3980,7 +4222,7 @@ var BaseMCPClient = class {
3980
4222
  ...serverConfig,
3981
4223
  authProvider: oauthProvider
3982
4224
  };
3983
- } else if ("authProvider" in serverConfig && serverConfig.authProvider && isOAuthClientProvider(serverConfig.authProvider)) {
4225
+ } else if ("authProvider" in serverConfig && serverConfig.authProvider && isOAuthClientProvider2(serverConfig.authProvider)) {
3984
4226
  oauthProvider = serverConfig.authProvider;
3985
4227
  }
3986
4228
  const openSession = async () => {
@@ -4320,6 +4562,7 @@ var BrowserMCPClient = class _BrowserMCPClient extends BaseMCPClient {
4320
4562
  fetch: configuredFetch,
4321
4563
  authToken,
4322
4564
  authProvider,
4565
+ detectMixedAuth,
4323
4566
  wrapTransport,
4324
4567
  clientOptions,
4325
4568
  protocolNegotiation,
@@ -4344,6 +4587,7 @@ var BrowserMCPClient = class _BrowserMCPClient extends BaseMCPClient {
4344
4587
  fetch: configuredFetch ?? globalThis.fetch.bind(globalThis),
4345
4588
  authToken,
4346
4589
  authProvider,
4590
+ detectMixedAuth,
4347
4591
  wrapTransport,
4348
4592
  clientOptions,
4349
4593
  onSampling: resolved.onSampling,
@@ -4655,6 +4899,9 @@ function useMcpOperations(params) {
4655
4899
  });
4656
4900
  return result;
4657
4901
  } catch (error) {
4902
+ if (isOAuthInteractionRequired(error)) {
4903
+ params.onAuthorizationRequired(error);
4904
+ }
4658
4905
  params.addLog("error", `Tool "${name}" call failed:`, error);
4659
4906
  Tel.getInstance().trackUseMcpToolCall({
4660
4907
  toolName: name,
@@ -4666,7 +4913,7 @@ function useMcpOperations(params) {
4666
4913
  throw error;
4667
4914
  }
4668
4915
  },
4669
- [params.addLog]
4916
+ [params.addLog, params.onAuthorizationRequired]
4670
4917
  );
4671
4918
  const listResources = useCallback(async () => {
4672
4919
  const connection = requireConnection(params, "list resources");
@@ -4842,6 +5089,7 @@ function useMcp(options) {
4842
5089
  reconnectionOptions,
4843
5090
  preventAutoAuth = true,
4844
5091
  // Default to true - require explicit user action for OAuth
5092
+ detectMixedAuth = true,
4845
5093
  useRedirectFlow = false,
4846
5094
  // Default to false for backward compatibility (use popup)
4847
5095
  onPopupWindow,
@@ -5019,6 +5267,7 @@ function useMcp(options) {
5019
5267
  const [log, setLog] = useState([]);
5020
5268
  const [authUrl, setAuthUrl] = useState(void 0);
5021
5269
  const [authTokens, setAuthTokens] = useState(void 0);
5270
+ const [authorization, setAuthorization] = useState(void 0);
5022
5271
  const clientRef = useRef(null);
5023
5272
  const connectionRef = useRef(null);
5024
5273
  const authProviderRef = useRef(
@@ -5033,6 +5282,9 @@ function useMcp(options) {
5033
5282
  const retryScheduledRef = useRef(false);
5034
5283
  const popupFlowActiveRef = useRef(false);
5035
5284
  const stateRef = useRef(state);
5285
+ const authorizationRef = useRef(authorization);
5286
+ const authorizationServerUrlRef = useRef(url);
5287
+ authorizationRef.current = authorization;
5036
5288
  const autoReconnectRef = useRef(autoReconnect);
5037
5289
  const successfulTransportRef = useRef(null);
5038
5290
  const connectRef = useRef(null);
@@ -5099,6 +5351,24 @@ function useMcp(options) {
5099
5351
  },
5100
5352
  [instanceLogger]
5101
5353
  );
5354
+ const onAuthorizationRequired = useCallback2(
5355
+ (authError) => {
5356
+ const preparedAuthUrl = authProviderRef.current?.getLastAttemptedAuthUrl?.() ?? void 0;
5357
+ addLog(
5358
+ "info",
5359
+ "This server requires OAuth for the requested operation; waiting for authentication.",
5360
+ authError
5361
+ );
5362
+ const authorizationRequired = {
5363
+ ...authorizationRef.current ?? { mode: "mixed" },
5364
+ authenticated: false
5365
+ };
5366
+ authorizationRef.current = authorizationRequired;
5367
+ setAuthorization(authorizationRequired);
5368
+ if (preparedAuthUrl) setAuthUrl(preparedAuthUrl);
5369
+ },
5370
+ [addLog]
5371
+ );
5102
5372
  const connectionOperations = useMcpOperations({
5103
5373
  stateRef,
5104
5374
  connectionRef,
@@ -5109,7 +5379,8 @@ function useMcp(options) {
5109
5379
  setResourceTemplates,
5110
5380
  setPrompts,
5111
5381
  setSkills,
5112
- addLog
5382
+ addLog,
5383
+ onAuthorizationRequired
5113
5384
  });
5114
5385
  const disconnect = useCallback2(
5115
5386
  async (quiet = false) => {
@@ -5250,6 +5521,11 @@ function useMcp(options) {
5250
5521
  connectingRef.current = true;
5251
5522
  connectEpochRef.current += 1;
5252
5523
  connectAttemptRef.current += 1;
5524
+ if (authorizationServerUrlRef.current !== url) {
5525
+ authorizationServerUrlRef.current = url;
5526
+ authorizationRef.current = void 0;
5527
+ setAuthorization(void 0);
5528
+ }
5253
5529
  setError(void 0);
5254
5530
  setAuthUrl(void 0);
5255
5531
  successfulTransportRef.current = null;
@@ -5336,6 +5612,7 @@ function useMcp(options) {
5336
5612
  // Protocol era negotiation mode ("legacy" | "auto" | { pin }); the
5337
5613
  // connector defaults to automatic v1/v2 negotiation.
5338
5614
  ...protocolNegotiation !== void 0 && { protocolNegotiation },
5615
+ detectMixedAuth,
5339
5616
  // Pass user-configurable reconnection options, or when autoReconnect
5340
5617
  // is disabled, disable SDK transport reconnection to prevent
5341
5618
  // unwanted GET polling requests
@@ -5467,6 +5744,62 @@ function useMcp(options) {
5467
5744
  }).catch(() => {
5468
5745
  });
5469
5746
  setTools(connection.tools || []);
5747
+ const {
5748
+ server: serverInfo2,
5749
+ capabilities: capabilities2,
5750
+ protocolEra: protocolEra2,
5751
+ protocolVersion: protocolVersion2,
5752
+ instructions: instructions2,
5753
+ extensions: extensions2,
5754
+ authorization: connectionAuthorization
5755
+ } = connection.info;
5756
+ if (connectionAuthorization) {
5757
+ setAuthorization(connectionAuthorization);
5758
+ authorizationRef.current = connectionAuthorization;
5759
+ }
5760
+ setProtocolEra(protocolEra2);
5761
+ setProtocolVersion(protocolVersion2);
5762
+ setInstructions(instructions2);
5763
+ setExtensions(extensions2);
5764
+ if (serverInfo2) {
5765
+ addLog("debug", "Server info:", serverInfo2);
5766
+ setServerInfo(serverInfo2);
5767
+ iconLoadingPromiseRef.current = loadServerIcon({
5768
+ serverInfo: serverInfo2,
5769
+ url,
5770
+ isMounted: () => isMountedRef.current,
5771
+ setServerInfo,
5772
+ addLog
5773
+ });
5774
+ }
5775
+ if (capabilities2) {
5776
+ addLog("debug", "Server capabilities:", capabilities2);
5777
+ setCapabilities(capabilities2);
5778
+ }
5779
+ successfulTransportRef.current = transportTypeParam;
5780
+ setState("ready");
5781
+ const discoverAuthorizationAfterReady = () => {
5782
+ if (!isMountedRef.current || connectionRef.current !== connection) {
5783
+ return;
5784
+ }
5785
+ const authorizationDiscovery = connection.discoverAuthorization?.();
5786
+ if (authorizationDiscovery) {
5787
+ void authorizationDiscovery.then((discovered) => {
5788
+ if (!discovered || !isMountedRef.current || connectionRef.current !== connection) {
5789
+ return;
5790
+ }
5791
+ authorizationRef.current = discovered;
5792
+ setAuthorization(discovered);
5793
+ });
5794
+ }
5795
+ };
5796
+ if (typeof globalThis.requestAnimationFrame === "function") {
5797
+ globalThis.requestAnimationFrame(() => {
5798
+ setTimeout(discoverAuthorizationAfterReady, 0);
5799
+ });
5800
+ } else {
5801
+ setTimeout(discoverAuthorizationAfterReady, 0);
5802
+ }
5470
5803
  const [resourcesResult, promptsResult, templatesResult] = await Promise.all([
5471
5804
  connection.listAllResources().catch((error2) => {
5472
5805
  addLog("warn", "Failed to load initial resources:", error2);
@@ -5495,19 +5828,7 @@ function useMcp(options) {
5495
5828
  setResources(resourcesResult.resources || []);
5496
5829
  setPrompts(promptsResult.prompts || []);
5497
5830
  setResourceTemplates(templatesResult.resourceTemplates || []);
5498
- const {
5499
- server: serverInfo2,
5500
- capabilities: capabilities2,
5501
- protocolEra: protocolEra2,
5502
- protocolVersion: protocolVersion2,
5503
- instructions: instructions2,
5504
- extensions: extensions2
5505
- } = connection.info;
5506
5831
  if (isMountedRef.current) {
5507
- setProtocolEra(protocolEra2);
5508
- setProtocolVersion(protocolVersion2);
5509
- setInstructions(instructions2);
5510
- setExtensions(extensions2);
5511
5832
  if (extensions2["io.modelcontextprotocol/skills"] !== void 0) {
5512
5833
  try {
5513
5834
  const result = await connection.listAllSkills();
@@ -5520,29 +5841,6 @@ function useMcp(options) {
5520
5841
  setSkills([]);
5521
5842
  }
5522
5843
  }
5523
- if (serverInfo2) {
5524
- addLog("debug", "Server info:", serverInfo2);
5525
- if (!isMountedRef.current) {
5526
- addLog("debug", "Skipping state update - component unmounted");
5527
- return "failed";
5528
- }
5529
- setServerInfo(serverInfo2);
5530
- iconLoadingPromiseRef.current = loadServerIcon({
5531
- serverInfo: serverInfo2,
5532
- url,
5533
- isMounted: () => isMountedRef.current,
5534
- setServerInfo,
5535
- addLog
5536
- });
5537
- }
5538
- if (capabilities2) {
5539
- addLog("debug", "Server capabilities:", capabilities2);
5540
- if (!isMountedRef.current) {
5541
- addLog("debug", "Skipping state update - component unmounted");
5542
- return "failed";
5543
- }
5544
- setCapabilities(capabilities2);
5545
- }
5546
5844
  if (authProviderRef.current) {
5547
5845
  const tokens = await authProviderRef.current.tokens?.();
5548
5846
  if (!isMountedRef.current) {
@@ -5553,6 +5851,14 @@ function useMcp(options) {
5553
5851
  return "failed";
5554
5852
  }
5555
5853
  if (tokens?.access_token) {
5854
+ if (authorizationRef.current?.mode === "mixed") {
5855
+ const authenticatedAuthorization = {
5856
+ ...authorizationRef.current,
5857
+ authenticated: true
5858
+ };
5859
+ setAuthorization(authenticatedAuthorization);
5860
+ authorizationRef.current = authenticatedAuthorization;
5861
+ }
5556
5862
  const expiresAt = getOAuthTokenExpiry(tokens);
5557
5863
  let tokenEndpoint = null;
5558
5864
  let resource = null;
@@ -5589,8 +5895,6 @@ function useMcp(options) {
5589
5895
  });
5590
5896
  }
5591
5897
  }
5592
- successfulTransportRef.current = transportTypeParam;
5593
- setState("ready");
5594
5898
  return "success";
5595
5899
  } catch (err) {
5596
5900
  const error2 = err;
@@ -5732,6 +6036,7 @@ function useMcp(options) {
5732
6036
  headers,
5733
6037
  transportType,
5734
6038
  preventAutoAuth,
6039
+ detectMixedAuth,
5735
6040
  useRedirectFlow,
5736
6041
  onPopupWindow,
5737
6042
  enabled,
@@ -5768,11 +6073,12 @@ function useMcp(options) {
5768
6073
  const authenticate = useCallback2(async () => {
5769
6074
  addLog("info", "Manual authentication requested...");
5770
6075
  const currentState = stateRef.current;
6076
+ const isOptionalMixedAuthentication = currentState === "ready" && authorizationRef.current?.mode === "mixed";
5771
6077
  if (currentState === "failed") {
5772
6078
  addLog("info", "Attempting to reconnect and authenticate via retry...");
5773
6079
  retry();
5774
- } else if (currentState === "pending_auth") {
5775
- addLog("info", "Proceeding with authentication from pending state...");
6080
+ } else if (currentState === "pending_auth" || currentState === "ready" && authorizationRef.current?.mode === "mixed" && !authorizationRef.current.authenticated) {
6081
+ addLog("info", "Proceeding with authentication...");
5776
6082
  try {
5777
6083
  assert(
5778
6084
  authProviderRef.current,
@@ -5891,16 +6197,16 @@ function useMcp(options) {
5891
6197
  case "cancelled":
5892
6198
  addLog(
5893
6199
  "warn",
5894
- "Authentication popup was closed before completing. Returning to pending_auth."
6200
+ isOptionalMixedAuthentication ? "Authentication popup was closed before completing. Public tools remain available." : "Authentication popup was closed before completing. Returning to pending_auth."
5895
6201
  );
5896
- setState("pending_auth");
6202
+ setState(isOptionalMixedAuthentication ? "ready" : "pending_auth");
5897
6203
  break;
5898
6204
  case "timeout":
5899
6205
  addLog(
5900
6206
  "warn",
5901
- "Authentication timed out waiting for the popup. Returning to pending_auth."
6207
+ isOptionalMixedAuthentication ? "Authentication timed out waiting for the popup. Public tools remain available." : "Authentication timed out waiting for the popup. Returning to pending_auth."
5902
6208
  );
5903
- setState("pending_auth");
6209
+ setState(isOptionalMixedAuthentication ? "ready" : "pending_auth");
5904
6210
  break;
5905
6211
  case "error":
5906
6212
  failConnection(`Authentication failed: ${result.error}`);
@@ -6189,6 +6495,7 @@ function useMcp(options) {
6189
6495
  log,
6190
6496
  authUrl,
6191
6497
  authTokens,
6498
+ authorization,
6192
6499
  client: clientRef.current,
6193
6500
  ...connectionOperations,
6194
6501
  retry,
@@ -6598,7 +6905,7 @@ function isSameMcpServer(left, right) {
6598
6905
  return left.id === right.id && sameSerializedValue(
6599
6906
  pickLiveServerConfig(left),
6600
6907
  pickLiveServerConfig(right)
6601
- ) && left.name === right.name && left.state === right.state && left.error === right.error && left.authUrl === right.authUrl && sameSerializedValue(left.authTokens, right.authTokens) && left.protocolEra === right.protocolEra && left.protocolVersion === right.protocolVersion && sameSerializedValue(left.serverInfo, right.serverInfo) && sameSerializedValue(left.capabilities, right.capabilities) && left.instructions === right.instructions && sameSerializedValue(left.extensions, right.extensions) && sameSerializedValue(left.tools, right.tools) && sameSerializedValue(left.resources, right.resources) && sameSerializedValue(left.resourceTemplates, right.resourceTemplates) && sameSerializedValue(left.prompts, right.prompts) && sameSerializedValue(left.notifications, right.notifications) && left.unreadNotificationCount === right.unreadNotificationCount && sameSerializedValue(
6908
+ ) && left.name === right.name && left.state === right.state && left.error === right.error && left.authUrl === right.authUrl && sameSerializedValue(left.authTokens, right.authTokens) && sameSerializedValue(left.authorization, right.authorization) && left.protocolEra === right.protocolEra && left.protocolVersion === right.protocolVersion && sameSerializedValue(left.serverInfo, right.serverInfo) && sameSerializedValue(left.capabilities, right.capabilities) && left.instructions === right.instructions && sameSerializedValue(left.extensions, right.extensions) && sameSerializedValue(left.tools, right.tools) && sameSerializedValue(left.resources, right.resources) && sameSerializedValue(left.resourceTemplates, right.resourceTemplates) && sameSerializedValue(left.prompts, right.prompts) && sameSerializedValue(left.notifications, right.notifications) && left.unreadNotificationCount === right.unreadNotificationCount && sameSerializedValue(
6602
6909
  left.pendingSamplingRequests,
6603
6910
  right.pendingSamplingRequests
6604
6911
  ) && sameSerializedValue(
@@ -6780,6 +7087,7 @@ function McpServerWrapper({
6780
7087
  mcp.instructions,
6781
7088
  mcp.extensions,
6782
7089
  mcp.authTokens,
7090
+ mcp.authorization,
6783
7091
  // Functions excluded - they're stable via useCallback in useMcp
6784
7092
  // mcp.log excluded - log changes shouldn't trigger provider updates
6785
7093
  // mcp.client excluded - client reference stability handled by manual check
@@ -8991,6 +9299,7 @@ export {
8991
9299
  getAllRpcLogs,
8992
9300
  getRpcLogs,
8993
9301
  getViewResourceUri,
9302
+ isOAuthInteractionRequired,
8994
9303
  isToolVisibleToModel,
8995
9304
  isViewResource,
8996
9305
  isViewTool,