@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.
- package/dist/.tsbuildinfo +1 -1
- package/dist/auth/browser.d.ts +2 -0
- package/dist/auth/browser.d.ts.map +1 -1
- package/dist/auth/storage.d.ts +12 -3
- package/dist/auth/storage.d.ts.map +1 -1
- package/dist/index-browser.js +215 -81
- package/dist/index-browser.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/react/McpClientProvider.d.ts.map +1 -1
- package/dist/react/index.d.ts +2 -1
- package/dist/react/index.d.ts.map +1 -1
- package/dist/react/index.js +361 -159
- package/dist/react/index.js.map +1 -1
- package/dist/react/storage.d.ts +10 -10
- package/dist/react/storage.d.ts.map +1 -1
- package/dist/react/types.d.ts +22 -5
- package/dist/react/types.d.ts.map +1 -1
- package/dist/react/useMcp-operations.d.ts.map +1 -1
- package/dist/react/view/inject-openai-file-apis.d.ts.map +1 -1
- package/package.json +2 -1
package/dist/react/index.js
CHANGED
|
@@ -251,6 +251,67 @@ var init_rpc_logger = __esm({
|
|
|
251
251
|
}
|
|
252
252
|
});
|
|
253
253
|
|
|
254
|
+
// src/react/types.ts
|
|
255
|
+
var PERSISTED_SERVER_CONFIG_KEYS = [
|
|
256
|
+
"url",
|
|
257
|
+
"displayName",
|
|
258
|
+
"enabled",
|
|
259
|
+
"oauthProxyUrl",
|
|
260
|
+
"connectionMode",
|
|
261
|
+
"autoProxyFallback",
|
|
262
|
+
"callbackUrl",
|
|
263
|
+
"storageKeyPrefix",
|
|
264
|
+
"logLevel",
|
|
265
|
+
"autoRetry",
|
|
266
|
+
"autoReconnect",
|
|
267
|
+
"reconnectionOptions",
|
|
268
|
+
"popupFeatures",
|
|
269
|
+
"preventAutoAuth",
|
|
270
|
+
"useRedirectFlow",
|
|
271
|
+
"protocolNegotiation",
|
|
272
|
+
"timeout",
|
|
273
|
+
"clientInfo"
|
|
274
|
+
];
|
|
275
|
+
function pickPersistedServerConfig(source) {
|
|
276
|
+
const out = {};
|
|
277
|
+
for (const key of PERSISTED_SERVER_CONFIG_KEYS) {
|
|
278
|
+
const value = source[key];
|
|
279
|
+
if (value !== void 0) {
|
|
280
|
+
out[key] = value;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
if (source.proxyConfig?.proxyAddress !== void 0) {
|
|
284
|
+
out.proxyConfig = { proxyAddress: source.proxyConfig.proxyAddress };
|
|
285
|
+
}
|
|
286
|
+
if (source.oauth) {
|
|
287
|
+
const oauth = {};
|
|
288
|
+
if (source.oauth.clientId !== void 0) {
|
|
289
|
+
oauth.clientId = source.oauth.clientId;
|
|
290
|
+
}
|
|
291
|
+
if (source.oauth.clientMetadataUrl !== void 0) {
|
|
292
|
+
oauth.clientMetadataUrl = source.oauth.clientMetadataUrl;
|
|
293
|
+
}
|
|
294
|
+
if (source.oauth.scope !== void 0) {
|
|
295
|
+
oauth.scope = source.oauth.scope;
|
|
296
|
+
}
|
|
297
|
+
if (Object.keys(oauth).length > 0) {
|
|
298
|
+
out.oauth = oauth;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
return out;
|
|
302
|
+
}
|
|
303
|
+
function pickLiveServerConfig(source) {
|
|
304
|
+
return {
|
|
305
|
+
...pickPersistedServerConfig(source),
|
|
306
|
+
...source.headers !== void 0 ? { headers: source.headers } : {},
|
|
307
|
+
...source.proxyConfig !== void 0 ? { proxyConfig: source.proxyConfig } : {},
|
|
308
|
+
...source.clientOptions !== void 0 ? { clientOptions: source.clientOptions } : {}
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
function toPersistedServerConfig(config) {
|
|
312
|
+
return pickPersistedServerConfig(config);
|
|
313
|
+
}
|
|
314
|
+
|
|
254
315
|
// src/react/useMcp.ts
|
|
255
316
|
import { auth as auth2 } from "@modelcontextprotocol/client";
|
|
256
317
|
|
|
@@ -1473,7 +1534,7 @@ var HttpConnector = class extends BaseConnector {
|
|
|
1473
1534
|
};
|
|
1474
1535
|
|
|
1475
1536
|
// src/utils/version.ts
|
|
1476
|
-
var VERSION = "2.0.0-beta.
|
|
1537
|
+
var VERSION = "2.0.0-beta.13";
|
|
1477
1538
|
function getPackageVersion() {
|
|
1478
1539
|
return VERSION;
|
|
1479
1540
|
}
|
|
@@ -1544,6 +1605,186 @@ function resolveClientOptions(clientOptions) {
|
|
|
1544
1605
|
};
|
|
1545
1606
|
}
|
|
1546
1607
|
|
|
1608
|
+
// src/auth/storage.ts
|
|
1609
|
+
var AUTH_CRYPTO_DATABASE = "mcp-use-oauth-crypto";
|
|
1610
|
+
var AUTH_CRYPTO_STORE = "keys";
|
|
1611
|
+
var AUTH_CRYPTO_KEY = "aes-gcm-v1";
|
|
1612
|
+
var textEncoder = new TextEncoder();
|
|
1613
|
+
var textDecoder = new TextDecoder();
|
|
1614
|
+
var LocalStorageKVStore = class {
|
|
1615
|
+
fallback = /* @__PURE__ */ new Map();
|
|
1616
|
+
keyPromise;
|
|
1617
|
+
durable = true;
|
|
1618
|
+
async get(key) {
|
|
1619
|
+
if (!this.durable) return this.fallback.get(key) ?? null;
|
|
1620
|
+
let stored;
|
|
1621
|
+
try {
|
|
1622
|
+
stored = localStorage.getItem(key);
|
|
1623
|
+
} catch {
|
|
1624
|
+
this.durable = false;
|
|
1625
|
+
return this.fallback.get(key) ?? null;
|
|
1626
|
+
}
|
|
1627
|
+
if (stored === null) return null;
|
|
1628
|
+
const envelope = parseEncryptedEnvelope(stored);
|
|
1629
|
+
if (!envelope) {
|
|
1630
|
+
await this.set(key, stored);
|
|
1631
|
+
return stored;
|
|
1632
|
+
}
|
|
1633
|
+
try {
|
|
1634
|
+
const cryptoKey = await this.getCryptoKey();
|
|
1635
|
+
const plaintext = await globalThis.crypto.subtle.decrypt(
|
|
1636
|
+
{
|
|
1637
|
+
name: "AES-GCM",
|
|
1638
|
+
iv: decodeBase64(envelope.iv),
|
|
1639
|
+
additionalData: textEncoder.encode(key)
|
|
1640
|
+
},
|
|
1641
|
+
cryptoKey,
|
|
1642
|
+
decodeBase64(envelope.ciphertext)
|
|
1643
|
+
);
|
|
1644
|
+
return textDecoder.decode(plaintext);
|
|
1645
|
+
} catch {
|
|
1646
|
+
await this.remove(key);
|
|
1647
|
+
return null;
|
|
1648
|
+
}
|
|
1649
|
+
}
|
|
1650
|
+
async set(key, value) {
|
|
1651
|
+
if (!this.durable) {
|
|
1652
|
+
this.fallback.set(key, value);
|
|
1653
|
+
return;
|
|
1654
|
+
}
|
|
1655
|
+
try {
|
|
1656
|
+
const cryptoKey = await this.getCryptoKey();
|
|
1657
|
+
const iv = globalThis.crypto.getRandomValues(new Uint8Array(12));
|
|
1658
|
+
const ciphertext = await globalThis.crypto.subtle.encrypt(
|
|
1659
|
+
{
|
|
1660
|
+
name: "AES-GCM",
|
|
1661
|
+
iv,
|
|
1662
|
+
additionalData: textEncoder.encode(key)
|
|
1663
|
+
},
|
|
1664
|
+
cryptoKey,
|
|
1665
|
+
textEncoder.encode(value)
|
|
1666
|
+
);
|
|
1667
|
+
const envelope = {
|
|
1668
|
+
v: 1,
|
|
1669
|
+
alg: "A256GCM",
|
|
1670
|
+
iv: encodeBase64(iv),
|
|
1671
|
+
ciphertext: encodeBase64(new Uint8Array(ciphertext))
|
|
1672
|
+
};
|
|
1673
|
+
localStorage.setItem(key, JSON.stringify(envelope));
|
|
1674
|
+
this.fallback.delete(key);
|
|
1675
|
+
} catch {
|
|
1676
|
+
this.durable = false;
|
|
1677
|
+
try {
|
|
1678
|
+
localStorage.removeItem(key);
|
|
1679
|
+
} catch {
|
|
1680
|
+
}
|
|
1681
|
+
this.fallback.set(key, value);
|
|
1682
|
+
}
|
|
1683
|
+
}
|
|
1684
|
+
remove(key) {
|
|
1685
|
+
this.fallback.delete(key);
|
|
1686
|
+
try {
|
|
1687
|
+
localStorage.removeItem(key);
|
|
1688
|
+
} catch {
|
|
1689
|
+
this.durable = false;
|
|
1690
|
+
}
|
|
1691
|
+
}
|
|
1692
|
+
keys() {
|
|
1693
|
+
const out = new Set(this.fallback.keys());
|
|
1694
|
+
if (this.durable) {
|
|
1695
|
+
try {
|
|
1696
|
+
for (let i = 0; i < localStorage.length; i++) {
|
|
1697
|
+
const key = localStorage.key(i);
|
|
1698
|
+
if (key) out.add(key);
|
|
1699
|
+
}
|
|
1700
|
+
} catch {
|
|
1701
|
+
this.durable = false;
|
|
1702
|
+
}
|
|
1703
|
+
}
|
|
1704
|
+
return [...out];
|
|
1705
|
+
}
|
|
1706
|
+
getCryptoKey() {
|
|
1707
|
+
this.keyPromise ??= getOrCreateCryptoKey();
|
|
1708
|
+
return this.keyPromise;
|
|
1709
|
+
}
|
|
1710
|
+
};
|
|
1711
|
+
function parseEncryptedEnvelope(value) {
|
|
1712
|
+
try {
|
|
1713
|
+
const parsed = JSON.parse(value);
|
|
1714
|
+
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") {
|
|
1715
|
+
return void 0;
|
|
1716
|
+
}
|
|
1717
|
+
return parsed;
|
|
1718
|
+
} catch {
|
|
1719
|
+
return void 0;
|
|
1720
|
+
}
|
|
1721
|
+
}
|
|
1722
|
+
async function getOrCreateCryptoKey() {
|
|
1723
|
+
if (!globalThis.crypto?.subtle || typeof indexedDB === "undefined") {
|
|
1724
|
+
throw new Error("Durable browser cryptography is unavailable");
|
|
1725
|
+
}
|
|
1726
|
+
const candidate = await globalThis.crypto.subtle.generateKey(
|
|
1727
|
+
{ name: "AES-GCM", length: 256 },
|
|
1728
|
+
false,
|
|
1729
|
+
["encrypt", "decrypt"]
|
|
1730
|
+
);
|
|
1731
|
+
const database = await openCryptoDatabase();
|
|
1732
|
+
try {
|
|
1733
|
+
return await new Promise((resolve, reject) => {
|
|
1734
|
+
const transaction = database.transaction(AUTH_CRYPTO_STORE, "readwrite");
|
|
1735
|
+
const store = transaction.objectStore(AUTH_CRYPTO_STORE);
|
|
1736
|
+
const request = store.get(AUTH_CRYPTO_KEY);
|
|
1737
|
+
let selected;
|
|
1738
|
+
request.onsuccess = () => {
|
|
1739
|
+
selected = request.result;
|
|
1740
|
+
if (!selected) {
|
|
1741
|
+
selected = candidate;
|
|
1742
|
+
store.put(candidate, AUTH_CRYPTO_KEY);
|
|
1743
|
+
}
|
|
1744
|
+
};
|
|
1745
|
+
request.onerror = () => reject(request.error);
|
|
1746
|
+
transaction.oncomplete = () => {
|
|
1747
|
+
if (selected) resolve(selected);
|
|
1748
|
+
else reject(new Error("OAuth encryption key was not initialized"));
|
|
1749
|
+
};
|
|
1750
|
+
transaction.onerror = () => reject(transaction.error);
|
|
1751
|
+
transaction.onabort = () => reject(transaction.error);
|
|
1752
|
+
});
|
|
1753
|
+
} finally {
|
|
1754
|
+
database.close();
|
|
1755
|
+
}
|
|
1756
|
+
}
|
|
1757
|
+
function openCryptoDatabase() {
|
|
1758
|
+
return new Promise((resolve, reject) => {
|
|
1759
|
+
const request = indexedDB.open(AUTH_CRYPTO_DATABASE, 1);
|
|
1760
|
+
request.onupgradeneeded = () => {
|
|
1761
|
+
const database = request.result;
|
|
1762
|
+
if (!database.objectStoreNames.contains(AUTH_CRYPTO_STORE)) {
|
|
1763
|
+
database.createObjectStore(AUTH_CRYPTO_STORE);
|
|
1764
|
+
}
|
|
1765
|
+
};
|
|
1766
|
+
request.onsuccess = () => resolve(request.result);
|
|
1767
|
+
request.onerror = () => reject(request.error);
|
|
1768
|
+
request.onblocked = () => reject(new Error("OAuth encryption database is blocked"));
|
|
1769
|
+
});
|
|
1770
|
+
}
|
|
1771
|
+
function encodeBase64(bytes) {
|
|
1772
|
+
let binary = "";
|
|
1773
|
+
for (const byte of bytes) binary += String.fromCharCode(byte);
|
|
1774
|
+
return btoa(binary);
|
|
1775
|
+
}
|
|
1776
|
+
function decodeBase64(value) {
|
|
1777
|
+
const binary = atob(value);
|
|
1778
|
+
const bytes = new Uint8Array(binary.length);
|
|
1779
|
+
for (let index = 0; index < binary.length; index++) {
|
|
1780
|
+
bytes[index] = binary.charCodeAt(index);
|
|
1781
|
+
}
|
|
1782
|
+
return bytes;
|
|
1783
|
+
}
|
|
1784
|
+
|
|
1785
|
+
// src/auth/session-store.ts
|
|
1786
|
+
import { validateClientMetadataUrl } from "@modelcontextprotocol/client";
|
|
1787
|
+
|
|
1547
1788
|
// src/auth/url.ts
|
|
1548
1789
|
function sanitizeUrl(raw) {
|
|
1549
1790
|
const abort = () => {
|
|
@@ -1568,29 +1809,7 @@ function sanitizeParam([k, v]) {
|
|
|
1568
1809
|
return `${encodeURIComponent(k)}${v.length > 0 ? `=${encodeURIComponent(v)}` : ""}`;
|
|
1569
1810
|
}
|
|
1570
1811
|
|
|
1571
|
-
// src/auth/storage.ts
|
|
1572
|
-
var LocalStorageKVStore = class {
|
|
1573
|
-
get(key) {
|
|
1574
|
-
return localStorage.getItem(key);
|
|
1575
|
-
}
|
|
1576
|
-
set(key, value) {
|
|
1577
|
-
localStorage.setItem(key, value);
|
|
1578
|
-
}
|
|
1579
|
-
remove(key) {
|
|
1580
|
-
localStorage.removeItem(key);
|
|
1581
|
-
}
|
|
1582
|
-
keys() {
|
|
1583
|
-
const out = [];
|
|
1584
|
-
for (let i = 0; i < localStorage.length; i++) {
|
|
1585
|
-
const k = localStorage.key(i);
|
|
1586
|
-
if (k) out.push(k);
|
|
1587
|
-
}
|
|
1588
|
-
return out;
|
|
1589
|
-
}
|
|
1590
|
-
};
|
|
1591
|
-
|
|
1592
1812
|
// src/auth/session-store.ts
|
|
1593
|
-
import { validateClientMetadataUrl } from "@modelcontextprotocol/client";
|
|
1594
1813
|
var OAuthSessionStore = class _OAuthSessionStore {
|
|
1595
1814
|
serverUrl;
|
|
1596
1815
|
storageKeyPrefix;
|
|
@@ -1902,16 +2121,25 @@ async function serializeBody(body) {
|
|
|
1902
2121
|
if (body instanceof Blob) return await body.text();
|
|
1903
2122
|
return body;
|
|
1904
2123
|
}
|
|
2124
|
+
function trimTrailingSlashes(value) {
|
|
2125
|
+
let end = value.length;
|
|
2126
|
+
while (end > 0 && value.charCodeAt(end - 1) === 47) {
|
|
2127
|
+
end--;
|
|
2128
|
+
}
|
|
2129
|
+
return value.slice(0, end);
|
|
2130
|
+
}
|
|
1905
2131
|
var BrowserOAuthClientProvider = class {
|
|
1906
2132
|
serverUrl;
|
|
1907
2133
|
staticClientInfo;
|
|
1908
2134
|
session;
|
|
2135
|
+
storage;
|
|
1909
2136
|
// Browser-only state
|
|
1910
2137
|
preventAutoAuth;
|
|
1911
2138
|
useRedirectFlow;
|
|
1912
2139
|
oauthProxyUrl;
|
|
1913
2140
|
connectionUrl;
|
|
1914
2141
|
proxyOAuthRequests;
|
|
2142
|
+
lastAttemptedAuthUrl = null;
|
|
1915
2143
|
onPopupWindow;
|
|
1916
2144
|
constructor(serverUrl, options = {}) {
|
|
1917
2145
|
if (options.staticClientInfo?.client_secret) {
|
|
@@ -1920,10 +2148,11 @@ var BrowserOAuthClientProvider = class {
|
|
|
1920
2148
|
);
|
|
1921
2149
|
}
|
|
1922
2150
|
this.serverUrl = serverUrl;
|
|
2151
|
+
this.storage = new LocalStorageKVStore();
|
|
1923
2152
|
this.session = new OAuthSessionStore(
|
|
1924
2153
|
serverUrl,
|
|
1925
2154
|
{ ...options, allowClientSecret: false },
|
|
1926
|
-
|
|
2155
|
+
this.storage
|
|
1927
2156
|
);
|
|
1928
2157
|
this.preventAutoAuth = options.preventAutoAuth;
|
|
1929
2158
|
this.useRedirectFlow = options.useRedirectFlow;
|
|
@@ -1988,8 +2217,8 @@ var BrowserOAuthClientProvider = class {
|
|
|
1988
2217
|
const [doc, ...suffixParts] = rest.split("/");
|
|
1989
2218
|
if (!doc) return url;
|
|
1990
2219
|
const suffix = suffixParts.length ? `/${suffixParts.join("/")}` : "";
|
|
1991
|
-
const connectionPath = connection.pathname
|
|
1992
|
-
const targetPath = target.pathname
|
|
2220
|
+
const connectionPath = trimTrailingSlashes(connection.pathname);
|
|
2221
|
+
const targetPath = trimTrailingSlashes(target.pathname);
|
|
1993
2222
|
const newSuffix = suffix && suffix === connectionPath ? targetPath : suffix;
|
|
1994
2223
|
return `${target.origin}/.well-known/${doc}${newSuffix}${requested.search}`;
|
|
1995
2224
|
} catch {
|
|
@@ -2140,6 +2369,7 @@ var BrowserOAuthClientProvider = class {
|
|
|
2140
2369
|
return this.session.tokens(ctx);
|
|
2141
2370
|
}
|
|
2142
2371
|
saveTokens(tokens, ctx) {
|
|
2372
|
+
this.lastAttemptedAuthUrl = null;
|
|
2143
2373
|
return this.session.saveTokens(tokens, ctx);
|
|
2144
2374
|
}
|
|
2145
2375
|
async clientInformation(ctx) {
|
|
@@ -2206,16 +2436,21 @@ var BrowserOAuthClientProvider = class {
|
|
|
2206
2436
|
* use `redirectToAuthorization` for that.
|
|
2207
2437
|
*/
|
|
2208
2438
|
async prepareAuthorizationUrl(authorizationUrl) {
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2439
|
+
const prepared = await this.session.storeAuthorizationState(
|
|
2440
|
+
authorizationUrl,
|
|
2441
|
+
{
|
|
2442
|
+
extraProviderOptions: {
|
|
2443
|
+
oauthProxyUrl: this.oauthProxyUrl,
|
|
2444
|
+
...this.clientMetadataUrl ? { clientMetadataUrl: this.clientMetadataUrl } : {},
|
|
2445
|
+
...this.staticClientInfo ? { staticClientInfo: this.staticClientInfo } : {},
|
|
2446
|
+
...this.scope ? { scope: this.scope } : {}
|
|
2447
|
+
},
|
|
2448
|
+
flowType: this.useRedirectFlow ? "redirect" : "popup",
|
|
2449
|
+
returnUrl: typeof window !== "undefined" ? window.location.href : void 0
|
|
2450
|
+
}
|
|
2451
|
+
);
|
|
2452
|
+
this.lastAttemptedAuthUrl = prepared;
|
|
2453
|
+
return prepared;
|
|
2219
2454
|
}
|
|
2220
2455
|
/**
|
|
2221
2456
|
* Redirects the user agent to the authorization URL, storing necessary state.
|
|
@@ -2267,64 +2502,24 @@ var BrowserOAuthClientProvider = class {
|
|
|
2267
2502
|
* Retrieves the last URL passed to `redirectToAuthorization`. Useful for manual fallback.
|
|
2268
2503
|
*/
|
|
2269
2504
|
getLastAttemptedAuthUrl() {
|
|
2270
|
-
|
|
2271
|
-
if (!storedUrl) return null;
|
|
2272
|
-
const storedCallbackUrl = localStorage.getItem(
|
|
2273
|
-
this.getKey("last_auth_callback_url")
|
|
2274
|
-
);
|
|
2275
|
-
if (storedCallbackUrl !== this.callbackUrl) {
|
|
2276
|
-
console.info(
|
|
2277
|
-
`[${this.storageKeyPrefix}] Recovering stale OAuth state whose callback cannot be verified.`
|
|
2278
|
-
);
|
|
2279
|
-
this.clearStorage();
|
|
2280
|
-
return null;
|
|
2281
|
-
}
|
|
2282
|
-
const sanitized = sanitizeUrl(storedUrl);
|
|
2283
|
-
try {
|
|
2284
|
-
const redirectUri = new URL(sanitized).searchParams.get("redirect_uri");
|
|
2285
|
-
if (redirectUri && new URL(redirectUri).toString() !== new URL(this.callbackUrl).toString()) {
|
|
2286
|
-
console.info(
|
|
2287
|
-
`[${this.storageKeyPrefix}] Recovering stale OAuth state after the Inspector callback path changed.`
|
|
2288
|
-
);
|
|
2289
|
-
this.clearStorage();
|
|
2290
|
-
return null;
|
|
2291
|
-
}
|
|
2292
|
-
} catch {
|
|
2293
|
-
this.clearStorage();
|
|
2294
|
-
return null;
|
|
2295
|
-
}
|
|
2296
|
-
return sanitized;
|
|
2505
|
+
return this.lastAttemptedAuthUrl;
|
|
2297
2506
|
}
|
|
2298
2507
|
clearStorage() {
|
|
2508
|
+
this.lastAttemptedAuthUrl = null;
|
|
2299
2509
|
const prefixPattern = `${this.storageKeyPrefix}_${this.serverUrlHash}_`;
|
|
2300
2510
|
const statePattern = `${this.storageKeyPrefix}:state_`;
|
|
2301
2511
|
const keysToRemove = [];
|
|
2302
2512
|
let count = 0;
|
|
2303
|
-
for (
|
|
2304
|
-
const key = localStorage.key(i);
|
|
2305
|
-
if (!key) continue;
|
|
2513
|
+
for (const key of this.storage.keys()) {
|
|
2306
2514
|
if (key.startsWith(prefixPattern)) {
|
|
2307
2515
|
keysToRemove.push(key);
|
|
2308
2516
|
} else if (key.startsWith(statePattern)) {
|
|
2309
|
-
|
|
2310
|
-
const item = localStorage.getItem(key);
|
|
2311
|
-
if (item) {
|
|
2312
|
-
const state = JSON.parse(item);
|
|
2313
|
-
if (state.serverUrlHash === this.serverUrlHash) {
|
|
2314
|
-
keysToRemove.push(key);
|
|
2315
|
-
}
|
|
2316
|
-
}
|
|
2317
|
-
} catch (e) {
|
|
2318
|
-
console.warn(
|
|
2319
|
-
`[${this.storageKeyPrefix}] Error parsing state key ${key} during clearStorage:`,
|
|
2320
|
-
e
|
|
2321
|
-
);
|
|
2322
|
-
}
|
|
2517
|
+
keysToRemove.push(key);
|
|
2323
2518
|
}
|
|
2324
2519
|
}
|
|
2325
2520
|
const uniqueKeysToRemove = [...new Set(keysToRemove)];
|
|
2326
2521
|
uniqueKeysToRemove.forEach((key) => {
|
|
2327
|
-
|
|
2522
|
+
this.storage.remove(key);
|
|
2328
2523
|
count++;
|
|
2329
2524
|
});
|
|
2330
2525
|
return count;
|
|
@@ -5915,45 +6110,6 @@ import React, {
|
|
|
5915
6110
|
useState as useState3
|
|
5916
6111
|
} from "react";
|
|
5917
6112
|
|
|
5918
|
-
// src/react/types.ts
|
|
5919
|
-
var PERSISTED_SERVER_CONFIG_KEYS = [
|
|
5920
|
-
"url",
|
|
5921
|
-
"displayName",
|
|
5922
|
-
"enabled",
|
|
5923
|
-
"proxyConfig",
|
|
5924
|
-
"oauthProxyUrl",
|
|
5925
|
-
"connectionMode",
|
|
5926
|
-
"autoProxyFallback",
|
|
5927
|
-
"callbackUrl",
|
|
5928
|
-
"storageKeyPrefix",
|
|
5929
|
-
"headers",
|
|
5930
|
-
"logLevel",
|
|
5931
|
-
"autoRetry",
|
|
5932
|
-
"autoReconnect",
|
|
5933
|
-
"reconnectionOptions",
|
|
5934
|
-
"popupFeatures",
|
|
5935
|
-
"preventAutoAuth",
|
|
5936
|
-
"useRedirectFlow",
|
|
5937
|
-
"clientOptions",
|
|
5938
|
-
"protocolNegotiation",
|
|
5939
|
-
"timeout",
|
|
5940
|
-
"clientInfo",
|
|
5941
|
-
"oauth"
|
|
5942
|
-
];
|
|
5943
|
-
function pickPersistedServerConfig(source) {
|
|
5944
|
-
const out = {};
|
|
5945
|
-
for (const key of PERSISTED_SERVER_CONFIG_KEYS) {
|
|
5946
|
-
const value = source[key];
|
|
5947
|
-
if (value !== void 0) {
|
|
5948
|
-
out[key] = value;
|
|
5949
|
-
}
|
|
5950
|
-
}
|
|
5951
|
-
return out;
|
|
5952
|
-
}
|
|
5953
|
-
function toPersistedServerConfig(config) {
|
|
5954
|
-
return pickPersistedServerConfig(config);
|
|
5955
|
-
}
|
|
5956
|
-
|
|
5957
6113
|
// src/react/useMcpServerQueues.ts
|
|
5958
6114
|
import { useCallback as useCallback3, useEffect as useEffect2, useRef as useRef2, useState as useState2 } from "react";
|
|
5959
6115
|
var MAX_NOTIFICATIONS = 500;
|
|
@@ -6140,8 +6296,8 @@ function sameSerializedValue(left, right) {
|
|
|
6140
6296
|
}
|
|
6141
6297
|
function isSameMcpServer(left, right) {
|
|
6142
6298
|
return left.id === right.id && sameSerializedValue(
|
|
6143
|
-
|
|
6144
|
-
|
|
6299
|
+
pickLiveServerConfig(left),
|
|
6300
|
+
pickLiveServerConfig(right)
|
|
6145
6301
|
) && 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(
|
|
6146
6302
|
left.pendingSamplingRequests,
|
|
6147
6303
|
right.pendingSamplingRequests
|
|
@@ -6275,7 +6431,7 @@ function McpServerWrapper({
|
|
|
6275
6431
|
}, [onUpdate]);
|
|
6276
6432
|
useEffect3(() => {
|
|
6277
6433
|
const server = {
|
|
6278
|
-
...
|
|
6434
|
+
...pickLiveServerConfig(options),
|
|
6279
6435
|
...mcp,
|
|
6280
6436
|
id,
|
|
6281
6437
|
displayName: displayName || options.displayName || id,
|
|
@@ -6622,8 +6778,8 @@ function McpClientProvider({
|
|
|
6622
6778
|
...options
|
|
6623
6779
|
};
|
|
6624
6780
|
if (sameSerializedValue(
|
|
6625
|
-
|
|
6626
|
-
|
|
6781
|
+
pickLiveServerConfig(currentConfig.options),
|
|
6782
|
+
pickLiveServerConfig(updatedOptions)
|
|
6627
6783
|
)) {
|
|
6628
6784
|
return;
|
|
6629
6785
|
}
|
|
@@ -6790,17 +6946,42 @@ var LocalStorageProvider = class {
|
|
|
6790
6946
|
getServers() {
|
|
6791
6947
|
try {
|
|
6792
6948
|
const stored = localStorage.getItem(this.storageKey);
|
|
6793
|
-
|
|
6794
|
-
|
|
6795
|
-
|
|
6949
|
+
if (!stored) return {};
|
|
6950
|
+
const parsed = JSON.parse(stored);
|
|
6951
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
6952
|
+
return {};
|
|
6953
|
+
}
|
|
6954
|
+
const sanitized = Object.fromEntries(
|
|
6955
|
+
Object.entries(parsed).flatMap(
|
|
6956
|
+
([id, config]) => config && typeof config === "object" && !Array.isArray(config) ? [
|
|
6957
|
+
[
|
|
6958
|
+
id,
|
|
6959
|
+
toPersistedServerConfig(config)
|
|
6960
|
+
]
|
|
6961
|
+
] : []
|
|
6962
|
+
)
|
|
6963
|
+
);
|
|
6964
|
+
const serialized = JSON.stringify(sanitized);
|
|
6965
|
+
if (serialized !== stored) {
|
|
6966
|
+
localStorage.setItem(this.storageKey, serialized);
|
|
6967
|
+
}
|
|
6968
|
+
return sanitized;
|
|
6969
|
+
} catch {
|
|
6970
|
+
console.error("[LocalStorageProvider] Failed to load servers.");
|
|
6796
6971
|
return {};
|
|
6797
6972
|
}
|
|
6798
6973
|
}
|
|
6799
6974
|
setServers(servers) {
|
|
6800
6975
|
try {
|
|
6801
|
-
|
|
6802
|
-
|
|
6803
|
-
|
|
6976
|
+
const sanitized = Object.fromEntries(
|
|
6977
|
+
Object.entries(servers).map(([id, config]) => [
|
|
6978
|
+
id,
|
|
6979
|
+
toPersistedServerConfig(config)
|
|
6980
|
+
])
|
|
6981
|
+
);
|
|
6982
|
+
localStorage.setItem(this.storageKey, JSON.stringify(sanitized));
|
|
6983
|
+
} catch {
|
|
6984
|
+
console.error("[LocalStorageProvider] Failed to save servers.");
|
|
6804
6985
|
}
|
|
6805
6986
|
}
|
|
6806
6987
|
setServer(id, config) {
|
|
@@ -6818,24 +6999,24 @@ var LocalStorageProvider = class {
|
|
|
6818
6999
|
try {
|
|
6819
7000
|
localStorage.removeItem(this.storageKey);
|
|
6820
7001
|
localStorage.removeItem(this.metadataKey);
|
|
6821
|
-
} catch
|
|
6822
|
-
console.error("[LocalStorageProvider] Failed to clear
|
|
7002
|
+
} catch {
|
|
7003
|
+
console.error("[LocalStorageProvider] Failed to clear.");
|
|
6823
7004
|
}
|
|
6824
7005
|
}
|
|
6825
7006
|
getAllMetadata() {
|
|
6826
7007
|
try {
|
|
6827
7008
|
const stored = localStorage.getItem(this.metadataKey);
|
|
6828
7009
|
return stored ? JSON.parse(stored) : {};
|
|
6829
|
-
} catch
|
|
6830
|
-
console.error("[LocalStorageProvider] Failed to load metadata
|
|
7010
|
+
} catch {
|
|
7011
|
+
console.error("[LocalStorageProvider] Failed to load metadata.");
|
|
6831
7012
|
return {};
|
|
6832
7013
|
}
|
|
6833
7014
|
}
|
|
6834
7015
|
setAllMetadata(metadata) {
|
|
6835
7016
|
try {
|
|
6836
7017
|
localStorage.setItem(this.metadataKey, JSON.stringify(metadata));
|
|
6837
|
-
} catch
|
|
6838
|
-
console.error("[LocalStorageProvider] Failed to save metadata
|
|
7018
|
+
} catch {
|
|
7019
|
+
console.error("[LocalStorageProvider] Failed to save metadata.");
|
|
6839
7020
|
}
|
|
6840
7021
|
}
|
|
6841
7022
|
getServerMetadata(id) {
|
|
@@ -6859,10 +7040,15 @@ var MemoryStorageProvider = class {
|
|
|
6859
7040
|
return { ...this.storage };
|
|
6860
7041
|
}
|
|
6861
7042
|
setServers(servers) {
|
|
6862
|
-
this.storage =
|
|
7043
|
+
this.storage = Object.fromEntries(
|
|
7044
|
+
Object.entries(servers).map(([id, config]) => [
|
|
7045
|
+
id,
|
|
7046
|
+
toPersistedServerConfig(config)
|
|
7047
|
+
])
|
|
7048
|
+
);
|
|
6863
7049
|
}
|
|
6864
7050
|
setServer(id, config) {
|
|
6865
|
-
this.storage[id] = config;
|
|
7051
|
+
this.storage[id] = toPersistedServerConfig(config);
|
|
6866
7052
|
}
|
|
6867
7053
|
removeServer(id) {
|
|
6868
7054
|
delete this.storage[id];
|
|
@@ -6942,32 +7128,46 @@ var OPENAI_FILE_APIS_SCRIPT = `<script>
|
|
|
6942
7128
|
})();
|
|
6943
7129
|
</script>`;
|
|
6944
7130
|
function injectOpenAiFileApis(html) {
|
|
6945
|
-
|
|
6946
|
-
|
|
6947
|
-
|
|
6948
|
-
|
|
6949
|
-
|
|
6950
|
-
|
|
6951
|
-
|
|
6952
|
-
|
|
6953
|
-
|
|
6954
|
-
"<
|
|
7131
|
+
const headEnd = findOpeningConstructEnd(html, "<head");
|
|
7132
|
+
if (headEnd !== void 0) {
|
|
7133
|
+
return insertAt(html, headEnd, OPENAI_FILE_APIS_SCRIPT);
|
|
7134
|
+
}
|
|
7135
|
+
const htmlEnd = findOpeningConstructEnd(html, "<html");
|
|
7136
|
+
if (htmlEnd !== void 0) {
|
|
7137
|
+
return insertAt(
|
|
7138
|
+
html,
|
|
7139
|
+
htmlEnd,
|
|
7140
|
+
"<head>" + OPENAI_FILE_APIS_SCRIPT + "</head>"
|
|
6955
7141
|
);
|
|
6956
7142
|
}
|
|
6957
|
-
|
|
6958
|
-
|
|
6959
|
-
|
|
6960
|
-
|
|
6961
|
-
|
|
6962
|
-
|
|
6963
|
-
if (html.includes("<!DOCTYPE") || html.includes("<!doctype")) {
|
|
6964
|
-
return html.replace(
|
|
6965
|
-
/(<!DOCTYPE[^>]*>|<!doctype[^>]*>)/i,
|
|
6966
|
-
"$1<head>" + OPENAI_FILE_APIS_SCRIPT + "</head>"
|
|
7143
|
+
const doctypeEnd = findOpeningConstructEnd(html, "<!doctype");
|
|
7144
|
+
if (doctypeEnd !== void 0) {
|
|
7145
|
+
return insertAt(
|
|
7146
|
+
html,
|
|
7147
|
+
doctypeEnd,
|
|
7148
|
+
"<head>" + OPENAI_FILE_APIS_SCRIPT + "</head>"
|
|
6967
7149
|
);
|
|
6968
7150
|
}
|
|
6969
7151
|
return OPENAI_FILE_APIS_SCRIPT + html;
|
|
6970
7152
|
}
|
|
7153
|
+
function findOpeningConstructEnd(html, lowercasePrefix) {
|
|
7154
|
+
const lowercaseHtml = html.toLowerCase();
|
|
7155
|
+
let searchFrom = 0;
|
|
7156
|
+
while (searchFrom < lowercaseHtml.length) {
|
|
7157
|
+
const start = lowercaseHtml.indexOf(lowercasePrefix, searchFrom);
|
|
7158
|
+
if (start === -1) return void 0;
|
|
7159
|
+
const boundary = lowercaseHtml[start + lowercasePrefix.length];
|
|
7160
|
+
if (boundary === ">" || boundary === " " || boundary === " " || boundary === "\n" || boundary === "\r" || boundary === "\f") {
|
|
7161
|
+
const end = lowercaseHtml.indexOf(">", start + lowercasePrefix.length);
|
|
7162
|
+
return end === -1 ? void 0 : end + 1;
|
|
7163
|
+
}
|
|
7164
|
+
searchFrom = start + lowercasePrefix.length;
|
|
7165
|
+
}
|
|
7166
|
+
return void 0;
|
|
7167
|
+
}
|
|
7168
|
+
function insertAt(value, index, addition) {
|
|
7169
|
+
return value.slice(0, index) + addition + value.slice(index);
|
|
7170
|
+
}
|
|
6971
7171
|
|
|
6972
7172
|
// src/react/view/resolve-view-resource.ts
|
|
6973
7173
|
function resolveViewResource(options) {
|
|
@@ -8098,10 +8298,12 @@ export {
|
|
|
8098
8298
|
isViewTool,
|
|
8099
8299
|
onMcpAuthorization,
|
|
8100
8300
|
parseCustomProps,
|
|
8301
|
+
pickPersistedServerConfig,
|
|
8101
8302
|
resolveViewResource,
|
|
8102
8303
|
setTelemetrySource,
|
|
8103
8304
|
specTypeSchemas,
|
|
8104
8305
|
subscribeToRpcLogs,
|
|
8306
|
+
toPersistedServerConfig,
|
|
8105
8307
|
useMcp,
|
|
8106
8308
|
useMcpClient,
|
|
8107
8309
|
useMcpServer
|