@mcp-use/client 2.0.0-beta.12 → 2.0.0-beta.13

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.
@@ -41,11 +41,13 @@ export declare class BrowserOAuthClientProvider implements OAuthClientProvider {
41
41
  readonly serverUrl: string;
42
42
  readonly staticClientInfo?: OAuthClientInformation;
43
43
  private session;
44
+ private readonly storage;
44
45
  readonly preventAutoAuth?: boolean;
45
46
  private useRedirectFlow?;
46
47
  private oauthProxyUrl?;
47
48
  private connectionUrl?;
48
49
  private proxyOAuthRequests;
50
+ private lastAttemptedAuthUrl;
49
51
  readonly onPopupWindow: ((url: string, features: string, window: globalThis.Window | null) => void) | undefined;
50
52
  constructor(serverUrl: string, options?: BrowserOAuthOptions);
51
53
  get storageKeyPrefix(): string;
@@ -1 +1 @@
1
- {"version":3,"file":"browser.d.ts","sourceRoot":"","sources":["../../src/auth/browser.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"browser.d.ts","sourceRoot":"","sources":["../../src/auth/browser.ts"],"names":[],"mappings":"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"}
@@ -12,14 +12,23 @@ export interface KVStore {
12
12
  keys(): Promise<string[]> | string[];
13
13
  }
14
14
  /**
15
- * `KVStore` implementation backed by `globalThis.localStorage`.
15
+ * Encrypted `KVStore` backed by `globalThis.localStorage`.
16
+ *
17
+ * Values use AES-256-GCM with a non-extractable origin key held by IndexedDB.
18
+ * Legacy plaintext values are encrypted on first read. When durable browser
19
+ * cryptography is unavailable, the store removes plaintext and falls back to
20
+ * memory for the lifetime of this instance.
16
21
  *
17
22
  * @internal
18
23
  */
19
24
  export declare class LocalStorageKVStore implements KVStore {
20
- get(key: string): string | null;
21
- set(key: string, value: string): void;
25
+ private readonly fallback;
26
+ private keyPromise;
27
+ private durable;
28
+ get(key: string): Promise<string | null>;
29
+ set(key: string, value: string): Promise<void>;
22
30
  remove(key: string): void;
23
31
  keys(): string[];
32
+ private getCryptoKey;
24
33
  }
25
34
  //# sourceMappingURL=storage.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../src/auth/storage.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,WAAW,OAAO;IACtB,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,GAAG,MAAM,GAAG,IAAI,CAAC;IACzD,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IACtD,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAC1C,IAAI,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC,GAAG,MAAM,EAAE,CAAC;CACtC;AAED;;;;GAIG;AACH,qBAAa,mBAAoB,YAAW,OAAO;IACjD,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAI/B,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAIrC,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAIzB,IAAI,IAAI,MAAM,EAAE;CAQjB"}
1
+ {"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../src/auth/storage.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,WAAW,OAAO;IACtB,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,GAAG,MAAM,GAAG,IAAI,CAAC;IACzD,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IACtD,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAC1C,IAAI,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC,GAAG,MAAM,EAAE,CAAC;CACtC;AAeD;;;;;;;;;GASG;AACH,qBAAa,mBAAoB,YAAW,OAAO;IACjD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA6B;IACtD,OAAO,CAAC,UAAU,CAAiC;IACnD,OAAO,CAAC,OAAO,CAAQ;IAEjB,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAoCxC,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAqCpD,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IASzB,IAAI,IAAI,MAAM,EAAE;IAehB,OAAO,CAAC,YAAY;CAIrB"}
@@ -128,7 +128,7 @@ var Logger = class {
128
128
  var logger = Logger.get();
129
129
 
130
130
  // src/utils/version.ts
131
- var VERSION = "2.0.0-beta.11";
131
+ var VERSION = "2.0.0-beta.13";
132
132
  function getPackageVersion() {
133
133
  return VERSION;
134
134
  }
@@ -589,6 +589,186 @@ setConnectorTelemetryTracker(
589
589
  (data) => Telemetry.getInstance().trackConnectorInit(data).catch(() => void 0)
590
590
  );
591
591
 
592
+ // src/auth/storage.ts
593
+ var AUTH_CRYPTO_DATABASE = "mcp-use-oauth-crypto";
594
+ var AUTH_CRYPTO_STORE = "keys";
595
+ var AUTH_CRYPTO_KEY = "aes-gcm-v1";
596
+ var textEncoder = new TextEncoder();
597
+ var textDecoder = new TextDecoder();
598
+ var LocalStorageKVStore = class {
599
+ fallback = /* @__PURE__ */ new Map();
600
+ keyPromise;
601
+ durable = true;
602
+ async get(key) {
603
+ if (!this.durable) return this.fallback.get(key) ?? null;
604
+ let stored;
605
+ try {
606
+ stored = localStorage.getItem(key);
607
+ } catch {
608
+ this.durable = false;
609
+ return this.fallback.get(key) ?? null;
610
+ }
611
+ if (stored === null) return null;
612
+ const envelope = parseEncryptedEnvelope(stored);
613
+ if (!envelope) {
614
+ await this.set(key, stored);
615
+ return stored;
616
+ }
617
+ try {
618
+ const cryptoKey = await this.getCryptoKey();
619
+ const plaintext = await globalThis.crypto.subtle.decrypt(
620
+ {
621
+ name: "AES-GCM",
622
+ iv: decodeBase64(envelope.iv),
623
+ additionalData: textEncoder.encode(key)
624
+ },
625
+ cryptoKey,
626
+ decodeBase64(envelope.ciphertext)
627
+ );
628
+ return textDecoder.decode(plaintext);
629
+ } catch {
630
+ await this.remove(key);
631
+ return null;
632
+ }
633
+ }
634
+ async set(key, value) {
635
+ if (!this.durable) {
636
+ this.fallback.set(key, value);
637
+ return;
638
+ }
639
+ try {
640
+ const cryptoKey = await this.getCryptoKey();
641
+ const iv = globalThis.crypto.getRandomValues(new Uint8Array(12));
642
+ const ciphertext = await globalThis.crypto.subtle.encrypt(
643
+ {
644
+ name: "AES-GCM",
645
+ iv,
646
+ additionalData: textEncoder.encode(key)
647
+ },
648
+ cryptoKey,
649
+ textEncoder.encode(value)
650
+ );
651
+ const envelope = {
652
+ v: 1,
653
+ alg: "A256GCM",
654
+ iv: encodeBase64(iv),
655
+ ciphertext: encodeBase64(new Uint8Array(ciphertext))
656
+ };
657
+ localStorage.setItem(key, JSON.stringify(envelope));
658
+ this.fallback.delete(key);
659
+ } catch {
660
+ this.durable = false;
661
+ try {
662
+ localStorage.removeItem(key);
663
+ } catch {
664
+ }
665
+ this.fallback.set(key, value);
666
+ }
667
+ }
668
+ remove(key) {
669
+ this.fallback.delete(key);
670
+ try {
671
+ localStorage.removeItem(key);
672
+ } catch {
673
+ this.durable = false;
674
+ }
675
+ }
676
+ keys() {
677
+ const out = new Set(this.fallback.keys());
678
+ if (this.durable) {
679
+ try {
680
+ for (let i = 0; i < localStorage.length; i++) {
681
+ const key = localStorage.key(i);
682
+ if (key) out.add(key);
683
+ }
684
+ } catch {
685
+ this.durable = false;
686
+ }
687
+ }
688
+ return [...out];
689
+ }
690
+ getCryptoKey() {
691
+ this.keyPromise ??= getOrCreateCryptoKey();
692
+ return this.keyPromise;
693
+ }
694
+ };
695
+ function parseEncryptedEnvelope(value) {
696
+ try {
697
+ const parsed = JSON.parse(value);
698
+ if (!parsed || typeof parsed !== "object" || !("v" in parsed) || parsed.v !== 1 || !("alg" in parsed) || parsed.alg !== "A256GCM" || !("iv" in parsed) || typeof parsed.iv !== "string" || !("ciphertext" in parsed) || typeof parsed.ciphertext !== "string") {
699
+ return void 0;
700
+ }
701
+ return parsed;
702
+ } catch {
703
+ return void 0;
704
+ }
705
+ }
706
+ async function getOrCreateCryptoKey() {
707
+ if (!globalThis.crypto?.subtle || typeof indexedDB === "undefined") {
708
+ throw new Error("Durable browser cryptography is unavailable");
709
+ }
710
+ const candidate = await globalThis.crypto.subtle.generateKey(
711
+ { name: "AES-GCM", length: 256 },
712
+ false,
713
+ ["encrypt", "decrypt"]
714
+ );
715
+ const database = await openCryptoDatabase();
716
+ try {
717
+ return await new Promise((resolve, reject) => {
718
+ const transaction = database.transaction(AUTH_CRYPTO_STORE, "readwrite");
719
+ const store = transaction.objectStore(AUTH_CRYPTO_STORE);
720
+ const request = store.get(AUTH_CRYPTO_KEY);
721
+ let selected;
722
+ request.onsuccess = () => {
723
+ selected = request.result;
724
+ if (!selected) {
725
+ selected = candidate;
726
+ store.put(candidate, AUTH_CRYPTO_KEY);
727
+ }
728
+ };
729
+ request.onerror = () => reject(request.error);
730
+ transaction.oncomplete = () => {
731
+ if (selected) resolve(selected);
732
+ else reject(new Error("OAuth encryption key was not initialized"));
733
+ };
734
+ transaction.onerror = () => reject(transaction.error);
735
+ transaction.onabort = () => reject(transaction.error);
736
+ });
737
+ } finally {
738
+ database.close();
739
+ }
740
+ }
741
+ function openCryptoDatabase() {
742
+ return new Promise((resolve, reject) => {
743
+ const request = indexedDB.open(AUTH_CRYPTO_DATABASE, 1);
744
+ request.onupgradeneeded = () => {
745
+ const database = request.result;
746
+ if (!database.objectStoreNames.contains(AUTH_CRYPTO_STORE)) {
747
+ database.createObjectStore(AUTH_CRYPTO_STORE);
748
+ }
749
+ };
750
+ request.onsuccess = () => resolve(request.result);
751
+ request.onerror = () => reject(request.error);
752
+ request.onblocked = () => reject(new Error("OAuth encryption database is blocked"));
753
+ });
754
+ }
755
+ function encodeBase64(bytes) {
756
+ let binary = "";
757
+ for (const byte of bytes) binary += String.fromCharCode(byte);
758
+ return btoa(binary);
759
+ }
760
+ function decodeBase64(value) {
761
+ const binary = atob(value);
762
+ const bytes = new Uint8Array(binary.length);
763
+ for (let index = 0; index < binary.length; index++) {
764
+ bytes[index] = binary.charCodeAt(index);
765
+ }
766
+ return bytes;
767
+ }
768
+
769
+ // src/auth/session-store.ts
770
+ import { validateClientMetadataUrl } from "@modelcontextprotocol/client";
771
+
592
772
  // src/auth/url.ts
593
773
  function sanitizeUrl(raw) {
594
774
  const abort = () => {
@@ -613,29 +793,7 @@ function sanitizeParam([k, v]) {
613
793
  return `${encodeURIComponent(k)}${v.length > 0 ? `=${encodeURIComponent(v)}` : ""}`;
614
794
  }
615
795
 
616
- // src/auth/storage.ts
617
- var LocalStorageKVStore = class {
618
- get(key) {
619
- return localStorage.getItem(key);
620
- }
621
- set(key, value) {
622
- localStorage.setItem(key, value);
623
- }
624
- remove(key) {
625
- localStorage.removeItem(key);
626
- }
627
- keys() {
628
- const out = [];
629
- for (let i = 0; i < localStorage.length; i++) {
630
- const k = localStorage.key(i);
631
- if (k) out.push(k);
632
- }
633
- return out;
634
- }
635
- };
636
-
637
796
  // src/auth/session-store.ts
638
- import { validateClientMetadataUrl } from "@modelcontextprotocol/client";
639
797
  var OAuthSessionStore = class _OAuthSessionStore {
640
798
  serverUrl;
641
799
  storageKeyPrefix;
@@ -947,16 +1105,25 @@ async function serializeBody(body) {
947
1105
  if (body instanceof Blob) return await body.text();
948
1106
  return body;
949
1107
  }
1108
+ function trimTrailingSlashes(value) {
1109
+ let end = value.length;
1110
+ while (end > 0 && value.charCodeAt(end - 1) === 47) {
1111
+ end--;
1112
+ }
1113
+ return value.slice(0, end);
1114
+ }
950
1115
  var BrowserOAuthClientProvider = class {
951
1116
  serverUrl;
952
1117
  staticClientInfo;
953
1118
  session;
1119
+ storage;
954
1120
  // Browser-only state
955
1121
  preventAutoAuth;
956
1122
  useRedirectFlow;
957
1123
  oauthProxyUrl;
958
1124
  connectionUrl;
959
1125
  proxyOAuthRequests;
1126
+ lastAttemptedAuthUrl = null;
960
1127
  onPopupWindow;
961
1128
  constructor(serverUrl, options = {}) {
962
1129
  if (options.staticClientInfo?.client_secret) {
@@ -965,10 +1132,11 @@ var BrowserOAuthClientProvider = class {
965
1132
  );
966
1133
  }
967
1134
  this.serverUrl = serverUrl;
1135
+ this.storage = new LocalStorageKVStore();
968
1136
  this.session = new OAuthSessionStore(
969
1137
  serverUrl,
970
1138
  { ...options, allowClientSecret: false },
971
- new LocalStorageKVStore()
1139
+ this.storage
972
1140
  );
973
1141
  this.preventAutoAuth = options.preventAutoAuth;
974
1142
  this.useRedirectFlow = options.useRedirectFlow;
@@ -1033,8 +1201,8 @@ var BrowserOAuthClientProvider = class {
1033
1201
  const [doc, ...suffixParts] = rest.split("/");
1034
1202
  if (!doc) return url;
1035
1203
  const suffix = suffixParts.length ? `/${suffixParts.join("/")}` : "";
1036
- const connectionPath = connection.pathname.replace(/\/+$/, "");
1037
- const targetPath = target.pathname.replace(/\/+$/, "");
1204
+ const connectionPath = trimTrailingSlashes(connection.pathname);
1205
+ const targetPath = trimTrailingSlashes(target.pathname);
1038
1206
  const newSuffix = suffix && suffix === connectionPath ? targetPath : suffix;
1039
1207
  return `${target.origin}/.well-known/${doc}${newSuffix}${requested.search}`;
1040
1208
  } catch {
@@ -1185,6 +1353,7 @@ var BrowserOAuthClientProvider = class {
1185
1353
  return this.session.tokens(ctx);
1186
1354
  }
1187
1355
  saveTokens(tokens, ctx) {
1356
+ this.lastAttemptedAuthUrl = null;
1188
1357
  return this.session.saveTokens(tokens, ctx);
1189
1358
  }
1190
1359
  async clientInformation(ctx) {
@@ -1251,16 +1420,21 @@ var BrowserOAuthClientProvider = class {
1251
1420
  * use `redirectToAuthorization` for that.
1252
1421
  */
1253
1422
  async prepareAuthorizationUrl(authorizationUrl) {
1254
- return this.session.storeAuthorizationState(authorizationUrl, {
1255
- extraProviderOptions: {
1256
- oauthProxyUrl: this.oauthProxyUrl,
1257
- ...this.clientMetadataUrl ? { clientMetadataUrl: this.clientMetadataUrl } : {},
1258
- ...this.staticClientInfo ? { staticClientInfo: this.staticClientInfo } : {},
1259
- ...this.scope ? { scope: this.scope } : {}
1260
- },
1261
- flowType: this.useRedirectFlow ? "redirect" : "popup",
1262
- returnUrl: typeof window !== "undefined" ? window.location.href : void 0
1263
- });
1423
+ const prepared = await this.session.storeAuthorizationState(
1424
+ authorizationUrl,
1425
+ {
1426
+ extraProviderOptions: {
1427
+ oauthProxyUrl: this.oauthProxyUrl,
1428
+ ...this.clientMetadataUrl ? { clientMetadataUrl: this.clientMetadataUrl } : {},
1429
+ ...this.staticClientInfo ? { staticClientInfo: this.staticClientInfo } : {},
1430
+ ...this.scope ? { scope: this.scope } : {}
1431
+ },
1432
+ flowType: this.useRedirectFlow ? "redirect" : "popup",
1433
+ returnUrl: typeof window !== "undefined" ? window.location.href : void 0
1434
+ }
1435
+ );
1436
+ this.lastAttemptedAuthUrl = prepared;
1437
+ return prepared;
1264
1438
  }
1265
1439
  /**
1266
1440
  * Redirects the user agent to the authorization URL, storing necessary state.
@@ -1312,64 +1486,24 @@ var BrowserOAuthClientProvider = class {
1312
1486
  * Retrieves the last URL passed to `redirectToAuthorization`. Useful for manual fallback.
1313
1487
  */
1314
1488
  getLastAttemptedAuthUrl() {
1315
- const storedUrl = localStorage.getItem(this.getKey("last_auth_url"));
1316
- if (!storedUrl) return null;
1317
- const storedCallbackUrl = localStorage.getItem(
1318
- this.getKey("last_auth_callback_url")
1319
- );
1320
- if (storedCallbackUrl !== this.callbackUrl) {
1321
- console.info(
1322
- `[${this.storageKeyPrefix}] Recovering stale OAuth state whose callback cannot be verified.`
1323
- );
1324
- this.clearStorage();
1325
- return null;
1326
- }
1327
- const sanitized = sanitizeUrl(storedUrl);
1328
- try {
1329
- const redirectUri = new URL(sanitized).searchParams.get("redirect_uri");
1330
- if (redirectUri && new URL(redirectUri).toString() !== new URL(this.callbackUrl).toString()) {
1331
- console.info(
1332
- `[${this.storageKeyPrefix}] Recovering stale OAuth state after the Inspector callback path changed.`
1333
- );
1334
- this.clearStorage();
1335
- return null;
1336
- }
1337
- } catch {
1338
- this.clearStorage();
1339
- return null;
1340
- }
1341
- return sanitized;
1489
+ return this.lastAttemptedAuthUrl;
1342
1490
  }
1343
1491
  clearStorage() {
1492
+ this.lastAttemptedAuthUrl = null;
1344
1493
  const prefixPattern = `${this.storageKeyPrefix}_${this.serverUrlHash}_`;
1345
1494
  const statePattern = `${this.storageKeyPrefix}:state_`;
1346
1495
  const keysToRemove = [];
1347
1496
  let count = 0;
1348
- for (let i = 0; i < localStorage.length; i++) {
1349
- const key = localStorage.key(i);
1350
- if (!key) continue;
1497
+ for (const key of this.storage.keys()) {
1351
1498
  if (key.startsWith(prefixPattern)) {
1352
1499
  keysToRemove.push(key);
1353
1500
  } else if (key.startsWith(statePattern)) {
1354
- try {
1355
- const item = localStorage.getItem(key);
1356
- if (item) {
1357
- const state = JSON.parse(item);
1358
- if (state.serverUrlHash === this.serverUrlHash) {
1359
- keysToRemove.push(key);
1360
- }
1361
- }
1362
- } catch (e) {
1363
- console.warn(
1364
- `[${this.storageKeyPrefix}] Error parsing state key ${key} during clearStorage:`,
1365
- e
1366
- );
1367
- }
1501
+ keysToRemove.push(key);
1368
1502
  }
1369
1503
  }
1370
1504
  const uniqueKeysToRemove = [...new Set(keysToRemove)];
1371
1505
  uniqueKeysToRemove.forEach((key) => {
1372
- localStorage.removeItem(key);
1506
+ this.storage.remove(key);
1373
1507
  count++;
1374
1508
  });
1375
1509
  return count;