@mcp-use/client 2.0.0-beta.12 → 2.0.0-beta.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/.tsbuildinfo +1 -1
- package/dist/auth/browser.d.ts +5 -0
- package/dist/auth/browser.d.ts.map +1 -1
- package/dist/auth/callback.d.ts.map +1 -1
- package/dist/auth/flow.d.ts.map +1 -1
- package/dist/auth/node.d.ts +16 -1
- package/dist/auth/node.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 +337 -143
- 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 +137 -47
- package/dist/index.js.map +1 -1
- package/dist/react/McpClientProvider.d.ts.map +1 -1
- package/dist/react/index.d.ts +3 -2
- package/dist/react/index.d.ts.map +1 -1
- package/dist/react/index.js +681 -293
- 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/token-expiry.d.ts +9 -0
- package/dist/react/token-expiry.d.ts.map +1 -0
- 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/useMcp.d.ts.map +1 -1
- package/dist/react/view/ViewRenderer.d.ts +3 -2
- package/dist/react/view/ViewRenderer.d.ts.map +1 -1
- package/dist/react/view/ext-apps-bridge.d.ts +1 -1
- package/dist/react/view/ext-apps-bridge.d.ts.map +1 -1
- package/dist/react/view/inject-openai-file-apis.d.ts.map +1 -1
- package/dist/react/view/types.d.ts +14 -4
- package/dist/react/view/types.d.ts.map +1 -1
- package/dist/react/view/view-host-policy.d.ts +24 -0
- package/dist/react/view/view-host-policy.d.ts.map +1 -0
- package/dist/telemetry/events.d.ts.map +1 -1
- package/dist/telemetry/tel-fetch.d.ts.map +1 -1
- package/dist/transport/connection-manager.d.ts +4 -0
- package/dist/transport/connection-manager.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.14";
|
|
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;
|
|
@@ -1849,7 +2068,7 @@ var OAuthSessionStore = class _OAuthSessionStore {
|
|
|
1849
2068
|
*/
|
|
1850
2069
|
async storeAuthorizationState(authorizationUrl, opts = {}) {
|
|
1851
2070
|
const state = globalThis.crypto.randomUUID();
|
|
1852
|
-
const stateKey = `${this.storageKeyPrefix}
|
|
2071
|
+
const stateKey = `${this.storageKeyPrefix}_${this.serverUrlHash}_state_${state}`;
|
|
1853
2072
|
const stateData = {
|
|
1854
2073
|
serverUrlHash: this.serverUrlHash,
|
|
1855
2074
|
expiry: Date.now() + 1e3 * 60 * 10,
|
|
@@ -1902,16 +2121,26 @@ 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;
|
|
2143
|
+
authorizationPending = false;
|
|
1915
2144
|
onPopupWindow;
|
|
1916
2145
|
constructor(serverUrl, options = {}) {
|
|
1917
2146
|
if (options.staticClientInfo?.client_secret) {
|
|
@@ -1920,10 +2149,11 @@ var BrowserOAuthClientProvider = class {
|
|
|
1920
2149
|
);
|
|
1921
2150
|
}
|
|
1922
2151
|
this.serverUrl = serverUrl;
|
|
2152
|
+
this.storage = new LocalStorageKVStore();
|
|
1923
2153
|
this.session = new OAuthSessionStore(
|
|
1924
2154
|
serverUrl,
|
|
1925
2155
|
{ ...options, allowClientSecret: false },
|
|
1926
|
-
|
|
2156
|
+
this.storage
|
|
1927
2157
|
);
|
|
1928
2158
|
this.preventAutoAuth = options.preventAutoAuth;
|
|
1929
2159
|
this.useRedirectFlow = options.useRedirectFlow;
|
|
@@ -1961,6 +2191,12 @@ var BrowserOAuthClientProvider = class {
|
|
|
1961
2191
|
getKey(keySuffix) {
|
|
1962
2192
|
return this.session.getKey(keySuffix);
|
|
1963
2193
|
}
|
|
2194
|
+
get hasPendingFlow() {
|
|
2195
|
+
return this.authorizationPending;
|
|
2196
|
+
}
|
|
2197
|
+
markFlowComplete() {
|
|
2198
|
+
this.authorizationPending = false;
|
|
2199
|
+
}
|
|
1964
2200
|
/**
|
|
1965
2201
|
* Re-anchor an SDK-derived OAuth discovery URL from the MCP connection
|
|
1966
2202
|
* (proxy) origin onto the actual MCP server.
|
|
@@ -1988,8 +2224,8 @@ var BrowserOAuthClientProvider = class {
|
|
|
1988
2224
|
const [doc, ...suffixParts] = rest.split("/");
|
|
1989
2225
|
if (!doc) return url;
|
|
1990
2226
|
const suffix = suffixParts.length ? `/${suffixParts.join("/")}` : "";
|
|
1991
|
-
const connectionPath = connection.pathname
|
|
1992
|
-
const targetPath = target.pathname
|
|
2227
|
+
const connectionPath = trimTrailingSlashes(connection.pathname);
|
|
2228
|
+
const targetPath = trimTrailingSlashes(target.pathname);
|
|
1993
2229
|
const newSuffix = suffix && suffix === connectionPath ? targetPath : suffix;
|
|
1994
2230
|
return `${target.origin}/.well-known/${doc}${newSuffix}${requested.search}`;
|
|
1995
2231
|
} catch {
|
|
@@ -2140,6 +2376,8 @@ var BrowserOAuthClientProvider = class {
|
|
|
2140
2376
|
return this.session.tokens(ctx);
|
|
2141
2377
|
}
|
|
2142
2378
|
saveTokens(tokens, ctx) {
|
|
2379
|
+
this.lastAttemptedAuthUrl = null;
|
|
2380
|
+
this.authorizationPending = false;
|
|
2143
2381
|
return this.session.saveTokens(tokens, ctx);
|
|
2144
2382
|
}
|
|
2145
2383
|
async clientInformation(ctx) {
|
|
@@ -2206,16 +2444,22 @@ var BrowserOAuthClientProvider = class {
|
|
|
2206
2444
|
* use `redirectToAuthorization` for that.
|
|
2207
2445
|
*/
|
|
2208
2446
|
async prepareAuthorizationUrl(authorizationUrl) {
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2447
|
+
const prepared = await this.session.storeAuthorizationState(
|
|
2448
|
+
authorizationUrl,
|
|
2449
|
+
{
|
|
2450
|
+
extraProviderOptions: {
|
|
2451
|
+
oauthProxyUrl: this.oauthProxyUrl,
|
|
2452
|
+
...this.clientMetadataUrl ? { clientMetadataUrl: this.clientMetadataUrl } : {},
|
|
2453
|
+
...this.staticClientInfo ? { staticClientInfo: this.staticClientInfo } : {},
|
|
2454
|
+
...this.scope ? { scope: this.scope } : {}
|
|
2455
|
+
},
|
|
2456
|
+
flowType: this.useRedirectFlow ? "redirect" : "popup",
|
|
2457
|
+
returnUrl: typeof window !== "undefined" ? window.location.href : void 0
|
|
2458
|
+
}
|
|
2459
|
+
);
|
|
2460
|
+
this.lastAttemptedAuthUrl = prepared;
|
|
2461
|
+
this.authorizationPending = true;
|
|
2462
|
+
return prepared;
|
|
2219
2463
|
}
|
|
2220
2464
|
/**
|
|
2221
2465
|
* Redirects the user agent to the authorization URL, storing necessary state.
|
|
@@ -2267,64 +2511,22 @@ var BrowserOAuthClientProvider = class {
|
|
|
2267
2511
|
* Retrieves the last URL passed to `redirectToAuthorization`. Useful for manual fallback.
|
|
2268
2512
|
*/
|
|
2269
2513
|
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;
|
|
2514
|
+
return this.lastAttemptedAuthUrl;
|
|
2297
2515
|
}
|
|
2298
2516
|
clearStorage() {
|
|
2517
|
+
this.lastAttemptedAuthUrl = null;
|
|
2518
|
+
this.authorizationPending = false;
|
|
2299
2519
|
const prefixPattern = `${this.storageKeyPrefix}_${this.serverUrlHash}_`;
|
|
2300
|
-
const statePattern = `${this.storageKeyPrefix}:state_`;
|
|
2301
2520
|
const keysToRemove = [];
|
|
2302
2521
|
let count = 0;
|
|
2303
|
-
for (
|
|
2304
|
-
const key = localStorage.key(i);
|
|
2305
|
-
if (!key) continue;
|
|
2522
|
+
for (const key of this.storage.keys()) {
|
|
2306
2523
|
if (key.startsWith(prefixPattern)) {
|
|
2307
2524
|
keysToRemove.push(key);
|
|
2308
|
-
} else if (key.startsWith(statePattern)) {
|
|
2309
|
-
try {
|
|
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
|
-
}
|
|
2323
2525
|
}
|
|
2324
2526
|
}
|
|
2325
2527
|
const uniqueKeysToRemove = [...new Set(keysToRemove)];
|
|
2326
2528
|
uniqueKeysToRemove.forEach((key) => {
|
|
2327
|
-
|
|
2529
|
+
this.storage.remove(key);
|
|
2328
2530
|
count++;
|
|
2329
2531
|
});
|
|
2330
2532
|
return count;
|
|
@@ -2355,16 +2557,13 @@ var MCPAgentExecutionEvent = class extends BaseTelemetryEvent {
|
|
|
2355
2557
|
return {
|
|
2356
2558
|
// Core execution info
|
|
2357
2559
|
execution_method: this.data.executionMethod,
|
|
2358
|
-
query: this.data.query,
|
|
2359
2560
|
query_length: this.data.query.length,
|
|
2360
2561
|
success: this.data.success,
|
|
2361
2562
|
// Agent configuration
|
|
2362
2563
|
model_provider: this.data.modelProvider,
|
|
2363
2564
|
model_name: this.data.modelName,
|
|
2364
2565
|
server_count: this.data.serverCount,
|
|
2365
|
-
server_identifiers: this.data.serverIdentifiers,
|
|
2366
2566
|
total_tools_available: this.data.totalToolsAvailable,
|
|
2367
|
-
tools_available_names: this.data.toolsAvailableNames,
|
|
2368
2567
|
max_steps_configured: this.data.maxStepsConfigured,
|
|
2369
2568
|
memory_enabled: this.data.memoryEnabled,
|
|
2370
2569
|
use_server_manager: this.data.useServerManager,
|
|
@@ -2375,8 +2574,6 @@ var MCPAgentExecutionEvent = class extends BaseTelemetryEvent {
|
|
|
2375
2574
|
// Execution results (always include, even if null)
|
|
2376
2575
|
steps_taken: this.data.stepsTaken ?? null,
|
|
2377
2576
|
tools_used_count: this.data.toolsUsedCount ?? null,
|
|
2378
|
-
tools_used_names: this.data.toolsUsedNames ?? null,
|
|
2379
|
-
response: this.data.response ?? null,
|
|
2380
2577
|
response_length: this.data.response ? this.data.response.length : null,
|
|
2381
2578
|
execution_time_ms: this.data.executionTimeMs ?? null,
|
|
2382
2579
|
error_type: this.data.errorType ?? null,
|
|
@@ -2472,21 +2669,72 @@ async function telFetch(url, init) {
|
|
|
2472
2669
|
}
|
|
2473
2670
|
var POSTHOG_HOST = "https://eu.i.posthog.com";
|
|
2474
2671
|
var POSTHOG_API_KEY = "phc_lyTtbYwvkdSbrcMQNPiKiiRWrrM1seyKIMjycSvItEI";
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
2672
|
+
var CONTENT_PROPERTY = /(^|_)(arguments?|args|body|command|headers?|location|message|query|response|secret|subject|token|uri|url|user_agent)(_|$)/i;
|
|
2673
|
+
var IDENTIFYING_PROPERTY = /(^|_)(server_identifiers?|server_names?|servers|tool_names?|tools_(available|used)_names)(_|$)/i;
|
|
2674
|
+
var AGGREGATE_PROPERTY = /(_count|_length|_duration(?:_ms)?|_time_ms|(^|_)num_[a-z0-9_]+)$/i;
|
|
2675
|
+
function normalizePropertyKey(key) {
|
|
2676
|
+
return key.replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/[^a-z0-9_$]+/gi, "_").toLowerCase();
|
|
2677
|
+
}
|
|
2678
|
+
function sanitizeValue(value, seen) {
|
|
2679
|
+
if (Array.isArray(value)) {
|
|
2680
|
+
if (seen.has(value)) {
|
|
2681
|
+
throw new TypeError("Cyclic telemetry properties are not supported");
|
|
2682
|
+
}
|
|
2683
|
+
seen.add(value);
|
|
2684
|
+
const sanitized = value.map((item) => sanitizeValue(item, seen));
|
|
2685
|
+
seen.delete(value);
|
|
2686
|
+
return sanitized;
|
|
2687
|
+
}
|
|
2688
|
+
if (value !== null && typeof value === "object" && (Object.getPrototypeOf(value) === Object.prototype || Object.getPrototypeOf(value) === null)) {
|
|
2689
|
+
if (seen.has(value)) {
|
|
2690
|
+
throw new TypeError("Cyclic telemetry properties are not supported");
|
|
2691
|
+
}
|
|
2692
|
+
seen.add(value);
|
|
2693
|
+
const sanitized = sanitizeProperties(
|
|
2694
|
+
value,
|
|
2695
|
+
seen
|
|
2696
|
+
);
|
|
2697
|
+
seen.delete(value);
|
|
2698
|
+
return sanitized;
|
|
2699
|
+
}
|
|
2700
|
+
return value;
|
|
2701
|
+
}
|
|
2702
|
+
function sanitizeProperties(properties, seen = /* @__PURE__ */ new WeakSet()) {
|
|
2703
|
+
const sanitized = {};
|
|
2704
|
+
for (const [key, value] of Object.entries(properties)) {
|
|
2705
|
+
const normalizedKey = normalizePropertyKey(key);
|
|
2706
|
+
if (AGGREGATE_PROPERTY.test(normalizedKey)) {
|
|
2707
|
+
if (value === null || typeof value === "number") {
|
|
2708
|
+
sanitized[key] = value;
|
|
2709
|
+
}
|
|
2710
|
+
continue;
|
|
2711
|
+
}
|
|
2712
|
+
if (IDENTIFYING_PROPERTY.test(normalizedKey) || CONTENT_PROPERTY.test(normalizedKey)) {
|
|
2713
|
+
continue;
|
|
2714
|
+
}
|
|
2715
|
+
sanitized[key] = sanitizeValue(value, seen);
|
|
2716
|
+
}
|
|
2717
|
+
return sanitized;
|
|
2718
|
+
}
|
|
2719
|
+
async function capturePostHog(params) {
|
|
2720
|
+
try {
|
|
2721
|
+
const host = params.host ?? POSTHOG_HOST;
|
|
2722
|
+
const apiKey = params.apiKey ?? POSTHOG_API_KEY;
|
|
2723
|
+
const body = JSON.stringify({
|
|
2483
2724
|
api_key: apiKey,
|
|
2484
2725
|
event: params.event,
|
|
2485
2726
|
distinct_id: params.distinctId,
|
|
2486
|
-
properties: params.properties,
|
|
2727
|
+
properties: sanitizeProperties(params.properties),
|
|
2487
2728
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
2488
|
-
})
|
|
2489
|
-
|
|
2729
|
+
});
|
|
2730
|
+
await telFetch(`${host}/i/v0/e/`, {
|
|
2731
|
+
method: "POST",
|
|
2732
|
+
headers: { "Content-Type": "application/json" },
|
|
2733
|
+
keepalive: true,
|
|
2734
|
+
body
|
|
2735
|
+
});
|
|
2736
|
+
} catch {
|
|
2737
|
+
}
|
|
2490
2738
|
}
|
|
2491
2739
|
|
|
2492
2740
|
// src/telemetry/telemetry.ts
|
|
@@ -2818,11 +3066,12 @@ async function completeOAuthFlow(provider, serverUrl, options = {}) {
|
|
|
2818
3066
|
throw new Error(`Unexpected OAuth auth() result: ${result}`);
|
|
2819
3067
|
}
|
|
2820
3068
|
}
|
|
2821
|
-
if (typeof flowProvider.getAuthorizationCode === "function") {
|
|
2822
|
-
const
|
|
3069
|
+
if (typeof flowProvider.getAuthorizationResponse === "function" || typeof flowProvider.getAuthorizationCode === "function") {
|
|
3070
|
+
const response = typeof flowProvider.getAuthorizationResponse === "function" ? await flowProvider.getAuthorizationResponse() : { code: await flowProvider.getAuthorizationCode() };
|
|
2823
3071
|
await auth(provider, {
|
|
2824
3072
|
serverUrl,
|
|
2825
|
-
authorizationCode: code,
|
|
3073
|
+
authorizationCode: response.code,
|
|
3074
|
+
...response.iss !== void 0 ? { iss: response.iss } : {},
|
|
2826
3075
|
fetchFn
|
|
2827
3076
|
});
|
|
2828
3077
|
return;
|
|
@@ -2836,6 +3085,8 @@ async function waitForBrowserAuthComplete(provider, timeoutMs) {
|
|
|
2836
3085
|
);
|
|
2837
3086
|
}
|
|
2838
3087
|
if (provider.useRedirectFlow) {
|
|
3088
|
+
await new Promise(() => {
|
|
3089
|
+
});
|
|
2839
3090
|
return;
|
|
2840
3091
|
}
|
|
2841
3092
|
const tokensKey = provider.getKey?.("tokens");
|
|
@@ -2852,25 +3103,29 @@ async function waitForBrowserAuthComplete(provider, timeoutMs) {
|
|
|
2852
3103
|
} catch {
|
|
2853
3104
|
}
|
|
2854
3105
|
}
|
|
2855
|
-
|
|
2856
|
-
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
|
|
2860
|
-
|
|
2861
|
-
|
|
2862
|
-
|
|
2863
|
-
|
|
2864
|
-
|
|
2865
|
-
|
|
2866
|
-
|
|
2867
|
-
|
|
2868
|
-
|
|
2869
|
-
|
|
2870
|
-
|
|
2871
|
-
|
|
2872
|
-
|
|
2873
|
-
|
|
3106
|
+
try {
|
|
3107
|
+
const result = await runAuthPopup({
|
|
3108
|
+
popup: null,
|
|
3109
|
+
state,
|
|
3110
|
+
tokensKey,
|
|
3111
|
+
timeoutMs
|
|
3112
|
+
});
|
|
3113
|
+
switch (result.kind) {
|
|
3114
|
+
case "success":
|
|
3115
|
+
return;
|
|
3116
|
+
case "cancelled":
|
|
3117
|
+
throw new Error("OAuth authentication was cancelled.");
|
|
3118
|
+
case "timeout":
|
|
3119
|
+
throw new Error(
|
|
3120
|
+
`OAuth callback not received within ${timeoutMs}ms. Ensure /oauth/callback calls onMcpAuthorization().`
|
|
3121
|
+
);
|
|
3122
|
+
case "error":
|
|
3123
|
+
throw new Error(result.error);
|
|
3124
|
+
default:
|
|
3125
|
+
throw new Error("Unexpected OAuth popup result");
|
|
3126
|
+
}
|
|
3127
|
+
} finally {
|
|
3128
|
+
provider.markFlowComplete?.();
|
|
2874
3129
|
}
|
|
2875
3130
|
}
|
|
2876
3131
|
|
|
@@ -4349,6 +4604,16 @@ function useMcpOperations(params) {
|
|
|
4349
4604
|
};
|
|
4350
4605
|
}
|
|
4351
4606
|
|
|
4607
|
+
// src/react/token-expiry.ts
|
|
4608
|
+
function getOAuthTokenExpiry(tokens) {
|
|
4609
|
+
try {
|
|
4610
|
+
const payload = JSON.parse(atob(tokens.access_token?.split(".")[1] ?? ""));
|
|
4611
|
+
if (typeof payload.exp === "number") return payload.exp * 1e3;
|
|
4612
|
+
} catch {
|
|
4613
|
+
}
|
|
4614
|
+
return typeof tokens.expires_in === "number" ? Date.now() + tokens.expires_in * 1e3 : void 0;
|
|
4615
|
+
}
|
|
4616
|
+
|
|
4352
4617
|
// src/react/useMcp.ts
|
|
4353
4618
|
var DEFAULT_RECONNECT_DELAY = 3e3;
|
|
4354
4619
|
var DEFAULT_RETRY_DELAY = 5e3;
|
|
@@ -5062,7 +5327,7 @@ function useMcp(options) {
|
|
|
5062
5327
|
return "failed";
|
|
5063
5328
|
}
|
|
5064
5329
|
if (tokens?.access_token) {
|
|
5065
|
-
const expiresAt = tokens
|
|
5330
|
+
const expiresAt = getOAuthTokenExpiry(tokens);
|
|
5066
5331
|
let tokenEndpoint = null;
|
|
5067
5332
|
let resource = null;
|
|
5068
5333
|
let clientCreds = null;
|
|
@@ -5172,8 +5437,10 @@ function useMcp(options) {
|
|
|
5172
5437
|
fetchFn: authProviderRef.current.getProxyFetch?.()
|
|
5173
5438
|
});
|
|
5174
5439
|
if (authResult === "REDIRECT") {
|
|
5175
|
-
const
|
|
5176
|
-
|
|
5440
|
+
const flowProvider = authProviderRef.current;
|
|
5441
|
+
const authResponse = await flowProvider.getAuthorizationResponse?.();
|
|
5442
|
+
const authCode = authResponse?.code ?? await flowProvider.getAuthorizationCode?.();
|
|
5443
|
+
if (typeof authCode !== "string") {
|
|
5177
5444
|
throw new Error(
|
|
5178
5445
|
"Authorization code not captured by headless provider"
|
|
5179
5446
|
);
|
|
@@ -5181,6 +5448,7 @@ function useMcp(options) {
|
|
|
5181
5448
|
await auth2(authProviderRef.current, {
|
|
5182
5449
|
serverUrl: url,
|
|
5183
5450
|
authorizationCode: authCode,
|
|
5451
|
+
...authResponse?.iss !== void 0 ? { iss: authResponse.iss } : {},
|
|
5184
5452
|
fetchFn: authProviderRef.current.getProxyFetch?.()
|
|
5185
5453
|
});
|
|
5186
5454
|
}
|
|
@@ -5775,20 +6043,14 @@ function renderResult(title, message, error, returnUrl) {
|
|
|
5775
6043
|
}
|
|
5776
6044
|
document.body.appendChild(container);
|
|
5777
6045
|
}
|
|
5778
|
-
function findStoredState(state) {
|
|
5779
|
-
const
|
|
5780
|
-
|
|
5781
|
-
|
|
5782
|
-
|
|
5783
|
-
|
|
5784
|
-
|
|
5785
|
-
|
|
5786
|
-
key = candidate;
|
|
5787
|
-
break;
|
|
5788
|
-
}
|
|
5789
|
-
}
|
|
5790
|
-
}
|
|
5791
|
-
const serialized = key ? localStorage.getItem(key) : null;
|
|
6046
|
+
async function findStoredState(state) {
|
|
6047
|
+
const store = new LocalStorageKVStore();
|
|
6048
|
+
const legacySuffix = `:state_${state}`;
|
|
6049
|
+
const scopedSuffix = `_state_${state}`;
|
|
6050
|
+
const key = (await store.keys()).find(
|
|
6051
|
+
(candidate) => candidate.endsWith(legacySuffix) || candidate.endsWith(scopedSuffix)
|
|
6052
|
+
);
|
|
6053
|
+
const serialized = key ? await store.get(key) : null;
|
|
5792
6054
|
if (!key || !serialized) {
|
|
5793
6055
|
throw new Error(`Invalid or expired OAuth state "${state}".`);
|
|
5794
6056
|
}
|
|
@@ -5796,10 +6058,10 @@ function findStoredState(state) {
|
|
|
5796
6058
|
try {
|
|
5797
6059
|
value = JSON.parse(serialized);
|
|
5798
6060
|
} catch {
|
|
5799
|
-
|
|
6061
|
+
await store.remove(key);
|
|
5800
6062
|
throw new Error("Failed to parse stored OAuth state.");
|
|
5801
6063
|
}
|
|
5802
|
-
return { key, value };
|
|
6064
|
+
return { key, value, store };
|
|
5803
6065
|
}
|
|
5804
6066
|
function redirectWithError(returnUrl, message) {
|
|
5805
6067
|
const url = new URL(returnUrl);
|
|
@@ -5858,17 +6120,19 @@ async function completeAuthorization() {
|
|
|
5858
6120
|
const callbackParams = new URLSearchParams(window.location.search);
|
|
5859
6121
|
const state = callbackParams.get("state");
|
|
5860
6122
|
let stateKey = null;
|
|
6123
|
+
let stateStore = null;
|
|
5861
6124
|
let storedState = null;
|
|
5862
6125
|
let provider = null;
|
|
5863
6126
|
try {
|
|
5864
6127
|
if (!state) {
|
|
5865
6128
|
throw new Error("OAuth callback is missing the state parameter.");
|
|
5866
6129
|
}
|
|
5867
|
-
const stored = findStoredState(state);
|
|
6130
|
+
const stored = await findStoredState(state);
|
|
5868
6131
|
stateKey = stored.key;
|
|
6132
|
+
stateStore = stored.store;
|
|
5869
6133
|
storedState = stored.value;
|
|
5870
6134
|
if (!storedState.expiry || storedState.expiry < Date.now()) {
|
|
5871
|
-
|
|
6135
|
+
await stateStore.remove(stateKey);
|
|
5872
6136
|
throw new Error(
|
|
5873
6137
|
"OAuth state has expired. Please start authentication again."
|
|
5874
6138
|
);
|
|
@@ -5883,7 +6147,7 @@ async function completeAuthorization() {
|
|
|
5883
6147
|
fetch: provider.getProxyFetch()
|
|
5884
6148
|
});
|
|
5885
6149
|
await transport.finishAuth(callbackParams);
|
|
5886
|
-
|
|
6150
|
+
await stateStore.remove(stateKey);
|
|
5887
6151
|
signalResult(true, void 0, storedState, {
|
|
5888
6152
|
state,
|
|
5889
6153
|
serverUrlHash: storedState.serverUrlHash
|
|
@@ -5891,8 +6155,12 @@ async function completeAuthorization() {
|
|
|
5891
6155
|
} catch (error) {
|
|
5892
6156
|
const message = error instanceof Error ? error.message : String(error);
|
|
5893
6157
|
console.error("[mcp-callback] OAuth callback failed:", error);
|
|
5894
|
-
if (stateKey)
|
|
5895
|
-
if (provider)
|
|
6158
|
+
if (stateKey && stateStore) await stateStore.remove(stateKey);
|
|
6159
|
+
if (provider) {
|
|
6160
|
+
await (stateStore ?? new LocalStorageKVStore()).remove(
|
|
6161
|
+
provider.getKey("last_auth_url")
|
|
6162
|
+
);
|
|
6163
|
+
}
|
|
5896
6164
|
signalResult(false, message, storedState, {
|
|
5897
6165
|
state,
|
|
5898
6166
|
serverUrlHash: storedState?.serverUrlHash
|
|
@@ -5915,45 +6183,6 @@ import React, {
|
|
|
5915
6183
|
useState as useState3
|
|
5916
6184
|
} from "react";
|
|
5917
6185
|
|
|
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
6186
|
// src/react/useMcpServerQueues.ts
|
|
5958
6187
|
import { useCallback as useCallback3, useEffect as useEffect2, useRef as useRef2, useState as useState2 } from "react";
|
|
5959
6188
|
var MAX_NOTIFICATIONS = 500;
|
|
@@ -6140,8 +6369,8 @@ function sameSerializedValue(left, right) {
|
|
|
6140
6369
|
}
|
|
6141
6370
|
function isSameMcpServer(left, right) {
|
|
6142
6371
|
return left.id === right.id && sameSerializedValue(
|
|
6143
|
-
|
|
6144
|
-
|
|
6372
|
+
pickLiveServerConfig(left),
|
|
6373
|
+
pickLiveServerConfig(right)
|
|
6145
6374
|
) && 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
6375
|
left.pendingSamplingRequests,
|
|
6147
6376
|
right.pendingSamplingRequests
|
|
@@ -6275,7 +6504,7 @@ function McpServerWrapper({
|
|
|
6275
6504
|
}, [onUpdate]);
|
|
6276
6505
|
useEffect3(() => {
|
|
6277
6506
|
const server = {
|
|
6278
|
-
...
|
|
6507
|
+
...pickLiveServerConfig(options),
|
|
6279
6508
|
...mcp,
|
|
6280
6509
|
id,
|
|
6281
6510
|
displayName: displayName || options.displayName || id,
|
|
@@ -6622,8 +6851,8 @@ function McpClientProvider({
|
|
|
6622
6851
|
...options
|
|
6623
6852
|
};
|
|
6624
6853
|
if (sameSerializedValue(
|
|
6625
|
-
|
|
6626
|
-
|
|
6854
|
+
pickLiveServerConfig(currentConfig.options),
|
|
6855
|
+
pickLiveServerConfig(updatedOptions)
|
|
6627
6856
|
)) {
|
|
6628
6857
|
return;
|
|
6629
6858
|
}
|
|
@@ -6790,17 +7019,48 @@ var LocalStorageProvider = class {
|
|
|
6790
7019
|
getServers() {
|
|
6791
7020
|
try {
|
|
6792
7021
|
const stored = localStorage.getItem(this.storageKey);
|
|
6793
|
-
|
|
6794
|
-
|
|
6795
|
-
|
|
7022
|
+
if (!stored) return {};
|
|
7023
|
+
const parsed = JSON.parse(stored);
|
|
7024
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
7025
|
+
return {};
|
|
7026
|
+
}
|
|
7027
|
+
const sanitized = Object.fromEntries(
|
|
7028
|
+
Object.entries(parsed).flatMap(
|
|
7029
|
+
([id, config]) => config && typeof config === "object" && !Array.isArray(config) ? [
|
|
7030
|
+
[
|
|
7031
|
+
id,
|
|
7032
|
+
toPersistedServerConfig(config)
|
|
7033
|
+
]
|
|
7034
|
+
] : []
|
|
7035
|
+
)
|
|
7036
|
+
);
|
|
7037
|
+
const serialized = JSON.stringify(sanitized);
|
|
7038
|
+
if (serialized !== stored) {
|
|
7039
|
+
try {
|
|
7040
|
+
localStorage.setItem(this.storageKey, serialized);
|
|
7041
|
+
} catch {
|
|
7042
|
+
console.error(
|
|
7043
|
+
"[LocalStorageProvider] Failed to persist sanitized servers."
|
|
7044
|
+
);
|
|
7045
|
+
}
|
|
7046
|
+
}
|
|
7047
|
+
return sanitized;
|
|
7048
|
+
} catch {
|
|
7049
|
+
console.error("[LocalStorageProvider] Failed to load servers.");
|
|
6796
7050
|
return {};
|
|
6797
7051
|
}
|
|
6798
7052
|
}
|
|
6799
7053
|
setServers(servers) {
|
|
6800
7054
|
try {
|
|
6801
|
-
|
|
6802
|
-
|
|
6803
|
-
|
|
7055
|
+
const sanitized = Object.fromEntries(
|
|
7056
|
+
Object.entries(servers).map(([id, config]) => [
|
|
7057
|
+
id,
|
|
7058
|
+
toPersistedServerConfig(config)
|
|
7059
|
+
])
|
|
7060
|
+
);
|
|
7061
|
+
localStorage.setItem(this.storageKey, JSON.stringify(sanitized));
|
|
7062
|
+
} catch {
|
|
7063
|
+
console.error("[LocalStorageProvider] Failed to save servers.");
|
|
6804
7064
|
}
|
|
6805
7065
|
}
|
|
6806
7066
|
setServer(id, config) {
|
|
@@ -6818,24 +7078,24 @@ var LocalStorageProvider = class {
|
|
|
6818
7078
|
try {
|
|
6819
7079
|
localStorage.removeItem(this.storageKey);
|
|
6820
7080
|
localStorage.removeItem(this.metadataKey);
|
|
6821
|
-
} catch
|
|
6822
|
-
console.error("[LocalStorageProvider] Failed to clear
|
|
7081
|
+
} catch {
|
|
7082
|
+
console.error("[LocalStorageProvider] Failed to clear.");
|
|
6823
7083
|
}
|
|
6824
7084
|
}
|
|
6825
7085
|
getAllMetadata() {
|
|
6826
7086
|
try {
|
|
6827
7087
|
const stored = localStorage.getItem(this.metadataKey);
|
|
6828
7088
|
return stored ? JSON.parse(stored) : {};
|
|
6829
|
-
} catch
|
|
6830
|
-
console.error("[LocalStorageProvider] Failed to load metadata
|
|
7089
|
+
} catch {
|
|
7090
|
+
console.error("[LocalStorageProvider] Failed to load metadata.");
|
|
6831
7091
|
return {};
|
|
6832
7092
|
}
|
|
6833
7093
|
}
|
|
6834
7094
|
setAllMetadata(metadata) {
|
|
6835
7095
|
try {
|
|
6836
7096
|
localStorage.setItem(this.metadataKey, JSON.stringify(metadata));
|
|
6837
|
-
} catch
|
|
6838
|
-
console.error("[LocalStorageProvider] Failed to save metadata
|
|
7097
|
+
} catch {
|
|
7098
|
+
console.error("[LocalStorageProvider] Failed to save metadata.");
|
|
6839
7099
|
}
|
|
6840
7100
|
}
|
|
6841
7101
|
getServerMetadata(id) {
|
|
@@ -6859,10 +7119,15 @@ var MemoryStorageProvider = class {
|
|
|
6859
7119
|
return { ...this.storage };
|
|
6860
7120
|
}
|
|
6861
7121
|
setServers(servers) {
|
|
6862
|
-
this.storage =
|
|
7122
|
+
this.storage = Object.fromEntries(
|
|
7123
|
+
Object.entries(servers).map(([id, config]) => [
|
|
7124
|
+
id,
|
|
7125
|
+
toPersistedServerConfig(config)
|
|
7126
|
+
])
|
|
7127
|
+
);
|
|
6863
7128
|
}
|
|
6864
7129
|
setServer(id, config) {
|
|
6865
|
-
this.storage[id] = config;
|
|
7130
|
+
this.storage[id] = toPersistedServerConfig(config);
|
|
6866
7131
|
}
|
|
6867
7132
|
removeServer(id) {
|
|
6868
7133
|
delete this.storage[id];
|
|
@@ -6942,32 +7207,58 @@ var OPENAI_FILE_APIS_SCRIPT = `<script>
|
|
|
6942
7207
|
})();
|
|
6943
7208
|
</script>`;
|
|
6944
7209
|
function injectOpenAiFileApis(html) {
|
|
6945
|
-
|
|
6946
|
-
|
|
6947
|
-
|
|
6948
|
-
|
|
6949
|
-
|
|
6950
|
-
|
|
6951
|
-
|
|
6952
|
-
|
|
6953
|
-
|
|
6954
|
-
"<
|
|
7210
|
+
const headEnd = findOpeningConstructEnd(html, "<head");
|
|
7211
|
+
if (headEnd !== void 0) {
|
|
7212
|
+
return insertAt(html, headEnd, OPENAI_FILE_APIS_SCRIPT);
|
|
7213
|
+
}
|
|
7214
|
+
const htmlEnd = findOpeningConstructEnd(html, "<html");
|
|
7215
|
+
if (htmlEnd !== void 0) {
|
|
7216
|
+
return insertAt(
|
|
7217
|
+
html,
|
|
7218
|
+
htmlEnd,
|
|
7219
|
+
"<head>" + OPENAI_FILE_APIS_SCRIPT + "</head>"
|
|
6955
7220
|
);
|
|
6956
7221
|
}
|
|
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>"
|
|
7222
|
+
const doctypeEnd = findOpeningConstructEnd(html, "<!doctype");
|
|
7223
|
+
if (doctypeEnd !== void 0) {
|
|
7224
|
+
return insertAt(
|
|
7225
|
+
html,
|
|
7226
|
+
doctypeEnd,
|
|
7227
|
+
"<head>" + OPENAI_FILE_APIS_SCRIPT + "</head>"
|
|
6967
7228
|
);
|
|
6968
7229
|
}
|
|
6969
7230
|
return OPENAI_FILE_APIS_SCRIPT + html;
|
|
6970
7231
|
}
|
|
7232
|
+
function findOpeningConstructEnd(html, lowercasePrefix) {
|
|
7233
|
+
const lowercaseHtml = html.toLowerCase();
|
|
7234
|
+
let searchFrom = 0;
|
|
7235
|
+
while (searchFrom < lowercaseHtml.length) {
|
|
7236
|
+
const start = lowercaseHtml.indexOf(lowercasePrefix, searchFrom);
|
|
7237
|
+
if (start === -1) return void 0;
|
|
7238
|
+
const boundary = lowercaseHtml[start + lowercasePrefix.length];
|
|
7239
|
+
if (boundary === ">" || boundary === " " || boundary === " " || boundary === "\n" || boundary === "\r" || boundary === "\f") {
|
|
7240
|
+
let quote;
|
|
7241
|
+
for (let index = start + lowercasePrefix.length; index < html.length; index++) {
|
|
7242
|
+
const character = html[index];
|
|
7243
|
+
if (quote) {
|
|
7244
|
+
if (character === quote) quote = void 0;
|
|
7245
|
+
continue;
|
|
7246
|
+
}
|
|
7247
|
+
if (character === '"' || character === "'") {
|
|
7248
|
+
quote = character;
|
|
7249
|
+
continue;
|
|
7250
|
+
}
|
|
7251
|
+
if (character === ">") return index + 1;
|
|
7252
|
+
}
|
|
7253
|
+
return void 0;
|
|
7254
|
+
}
|
|
7255
|
+
searchFrom = start + lowercasePrefix.length;
|
|
7256
|
+
}
|
|
7257
|
+
return void 0;
|
|
7258
|
+
}
|
|
7259
|
+
function insertAt(value, index, addition) {
|
|
7260
|
+
return value.slice(0, index) + addition + value.slice(index);
|
|
7261
|
+
}
|
|
6971
7262
|
|
|
6972
7263
|
// src/react/view/resolve-view-resource.ts
|
|
6973
7264
|
function resolveViewResource(options) {
|
|
@@ -7382,6 +7673,63 @@ var VIEW_DIMENSIONS = {
|
|
|
7382
7673
|
FULLSCREEN_HEADER_HEIGHT: 50
|
|
7383
7674
|
};
|
|
7384
7675
|
|
|
7676
|
+
// src/react/view/view-host-policy.ts
|
|
7677
|
+
function buildDefaultHostCapabilities({
|
|
7678
|
+
hasConnection,
|
|
7679
|
+
hasMessageHandler,
|
|
7680
|
+
hasModelContextHandler,
|
|
7681
|
+
hasLogHandler,
|
|
7682
|
+
messageCapabilities,
|
|
7683
|
+
modelContextCapabilities
|
|
7684
|
+
}) {
|
|
7685
|
+
return {
|
|
7686
|
+
openLinks: {},
|
|
7687
|
+
...hasConnection ? {
|
|
7688
|
+
serverTools: {},
|
|
7689
|
+
serverResources: {}
|
|
7690
|
+
} : {},
|
|
7691
|
+
...hasLogHandler ? { logging: {} } : {},
|
|
7692
|
+
...hasModelContextHandler ? { updateModelContext: modelContextCapabilities ?? { text: {} } } : {},
|
|
7693
|
+
...hasMessageHandler ? { message: messageCapabilities ?? { text: {} } } : {}
|
|
7694
|
+
};
|
|
7695
|
+
}
|
|
7696
|
+
function isToolVisibleToModel(tool) {
|
|
7697
|
+
if (!tool._meta || typeof tool._meta !== "object") return true;
|
|
7698
|
+
const ui = tool._meta.ui;
|
|
7699
|
+
if (!ui || typeof ui !== "object") return true;
|
|
7700
|
+
const visibility = ui.visibility;
|
|
7701
|
+
return !Array.isArray(visibility) || visibility.some((value) => value === "model");
|
|
7702
|
+
}
|
|
7703
|
+
async function dispatchUiMessage(handler, content) {
|
|
7704
|
+
if (!handler) {
|
|
7705
|
+
throw new Error("This host surface does not support ui/message");
|
|
7706
|
+
}
|
|
7707
|
+
if (content.length === 0) {
|
|
7708
|
+
throw new Error("ui/message requires at least one content block");
|
|
7709
|
+
}
|
|
7710
|
+
await handler(content);
|
|
7711
|
+
}
|
|
7712
|
+
function resolveRequestedDisplayMode({
|
|
7713
|
+
requested,
|
|
7714
|
+
current,
|
|
7715
|
+
hostAvailable,
|
|
7716
|
+
appAvailable
|
|
7717
|
+
}) {
|
|
7718
|
+
const hostModes = hostAvailable ?? ["inline"];
|
|
7719
|
+
const appModes = appAvailable ?? ["inline"];
|
|
7720
|
+
return hostModes.includes(requested) && appModes.includes(requested) ? requested : current;
|
|
7721
|
+
}
|
|
7722
|
+
function assertAppCanCallTool(tools, name) {
|
|
7723
|
+
const tool = tools?.find((candidate) => candidate.name === name);
|
|
7724
|
+
if (!tool) {
|
|
7725
|
+
throw new Error(`Tool "${name}" is not available to this app`);
|
|
7726
|
+
}
|
|
7727
|
+
const visibility = tool._meta?.ui?.visibility;
|
|
7728
|
+
if (visibility && !visibility.includes("app")) {
|
|
7729
|
+
throw new Error(`Tool "${name}" is not available to this app`);
|
|
7730
|
+
}
|
|
7731
|
+
}
|
|
7732
|
+
|
|
7385
7733
|
// src/react/view/view-detection.ts
|
|
7386
7734
|
function getViewResourceUri(toolMeta) {
|
|
7387
7735
|
const uri = toolMeta?.ui;
|
|
@@ -7401,15 +7749,6 @@ function isViewResource(mimeType) {
|
|
|
7401
7749
|
var DEFAULT_HOST_INFO = { name: "mcp-use-client", version: "2.0.0" };
|
|
7402
7750
|
var DEFAULT_TOOL_CALL_TIMEOUT = 6e5;
|
|
7403
7751
|
var SANDBOX_PROXY_READY = "ui/notifications/sandbox-proxy-ready";
|
|
7404
|
-
var DEFAULT_HOST_CAPABILITIES = {
|
|
7405
|
-
openLinks: {},
|
|
7406
|
-
serverTools: {},
|
|
7407
|
-
serverResources: {},
|
|
7408
|
-
logging: {},
|
|
7409
|
-
updateModelContext: { text: {} },
|
|
7410
|
-
// ponytail: always advertised; bridge.onmessage no-ops when onMessage unset
|
|
7411
|
-
message: { text: {} }
|
|
7412
|
-
};
|
|
7413
7752
|
function CloseIcon() {
|
|
7414
7753
|
return /* @__PURE__ */ React2.createElement(
|
|
7415
7754
|
"svg",
|
|
@@ -7473,6 +7812,8 @@ function ViewRendererBase({
|
|
|
7473
7812
|
hostInfo = DEFAULT_HOST_INFO,
|
|
7474
7813
|
hostContext,
|
|
7475
7814
|
hostCapabilities,
|
|
7815
|
+
messageCapabilities,
|
|
7816
|
+
modelContextCapabilities,
|
|
7476
7817
|
cspMode = "widget-declared",
|
|
7477
7818
|
displayMode: displayModeProp,
|
|
7478
7819
|
onDisplayModeChange,
|
|
@@ -7516,6 +7857,28 @@ function ViewRendererBase({
|
|
|
7516
7857
|
);
|
|
7517
7858
|
const [internalDisplayMode, setInternalDisplayMode] = useState4("inline");
|
|
7518
7859
|
const displayMode = displayModeProp ?? internalDisplayMode;
|
|
7860
|
+
const effectiveHostCapabilities = useMemo3(
|
|
7861
|
+
() => ({
|
|
7862
|
+
...buildDefaultHostCapabilities({
|
|
7863
|
+
hasConnection: source.kind === "live",
|
|
7864
|
+
hasMessageHandler: onMessage !== void 0,
|
|
7865
|
+
hasModelContextHandler: onModelContextUpdate !== void 0,
|
|
7866
|
+
hasLogHandler: onLog !== void 0,
|
|
7867
|
+
messageCapabilities,
|
|
7868
|
+
modelContextCapabilities
|
|
7869
|
+
}),
|
|
7870
|
+
...hostCapabilities
|
|
7871
|
+
}),
|
|
7872
|
+
[
|
|
7873
|
+
hostCapabilities,
|
|
7874
|
+
messageCapabilities,
|
|
7875
|
+
modelContextCapabilities,
|
|
7876
|
+
onLog,
|
|
7877
|
+
onMessage,
|
|
7878
|
+
onModelContextUpdate,
|
|
7879
|
+
source.kind
|
|
7880
|
+
]
|
|
7881
|
+
);
|
|
7519
7882
|
const effectiveHostContext = useMemo3(() => {
|
|
7520
7883
|
if (!hostContext) return hostContext;
|
|
7521
7884
|
if (hostContext.displayMode === displayMode) return hostContext;
|
|
@@ -7741,7 +8104,7 @@ function ViewRendererBase({
|
|
|
7741
8104
|
await readyPromise;
|
|
7742
8105
|
if (disposed) return;
|
|
7743
8106
|
const capabilities = {
|
|
7744
|
-
...
|
|
8107
|
+
...effectiveHostCapabilities,
|
|
7745
8108
|
sandbox: {
|
|
7746
8109
|
csp: cspMode === "permissive" ? void 0 : resolved.csp,
|
|
7747
8110
|
permissions: resolved.permissions
|
|
@@ -7750,75 +8113,92 @@ function ViewRendererBase({
|
|
|
7750
8113
|
bridge = new AppBridge(null, hostInfo, capabilities, {
|
|
7751
8114
|
hostContext: hostContextRef.current
|
|
7752
8115
|
});
|
|
7753
|
-
|
|
7754
|
-
|
|
7755
|
-
|
|
7756
|
-
|
|
7757
|
-
onMessageRef.current
|
|
7758
|
-
|
|
7759
|
-
|
|
7760
|
-
}
|
|
8116
|
+
if (capabilities.message) {
|
|
8117
|
+
bridge.onmessage = async ({
|
|
8118
|
+
content
|
|
8119
|
+
}) => {
|
|
8120
|
+
await dispatchUiMessage(onMessageRef.current, content);
|
|
8121
|
+
return {};
|
|
8122
|
+
};
|
|
8123
|
+
}
|
|
7761
8124
|
bridge.onopenlink = async ({ url }) => {
|
|
7762
8125
|
if (url) window.open(url, "_blank", "noopener,noreferrer");
|
|
7763
8126
|
return {};
|
|
7764
8127
|
};
|
|
7765
|
-
|
|
7766
|
-
|
|
7767
|
-
|
|
7768
|
-
|
|
7769
|
-
|
|
7770
|
-
|
|
7771
|
-
|
|
7772
|
-
|
|
7773
|
-
|
|
7774
|
-
|
|
7775
|
-
|
|
7776
|
-
|
|
7777
|
-
|
|
7778
|
-
|
|
7779
|
-
|
|
7780
|
-
|
|
7781
|
-
|
|
7782
|
-
|
|
7783
|
-
|
|
7784
|
-
|
|
7785
|
-
}
|
|
7786
|
-
|
|
7787
|
-
|
|
7788
|
-
|
|
7789
|
-
|
|
7790
|
-
|
|
7791
|
-
|
|
7792
|
-
|
|
7793
|
-
|
|
7794
|
-
|
|
8128
|
+
if (capabilities.serverTools) {
|
|
8129
|
+
bridge.oncalltool = (async ({
|
|
8130
|
+
name,
|
|
8131
|
+
arguments: args
|
|
8132
|
+
}) => {
|
|
8133
|
+
const conn = connectionRef.current;
|
|
8134
|
+
if (!conn) throw new Error("Server connection not available");
|
|
8135
|
+
assertAppCanCallTool(conn.tools, name);
|
|
8136
|
+
try {
|
|
8137
|
+
return await conn.callTool(name, args || {}, {
|
|
8138
|
+
timeout: toolCallTimeout,
|
|
8139
|
+
resetTimeoutOnProgress: true
|
|
8140
|
+
});
|
|
8141
|
+
} catch (error) {
|
|
8142
|
+
bridge?.sendToolCancelled({
|
|
8143
|
+
reason: error instanceof Error ? error.message : String(error)
|
|
8144
|
+
});
|
|
8145
|
+
throw error;
|
|
8146
|
+
}
|
|
8147
|
+
});
|
|
8148
|
+
}
|
|
8149
|
+
if (capabilities.serverResources) {
|
|
8150
|
+
bridge.onreadresource = (async ({
|
|
8151
|
+
uri
|
|
8152
|
+
}) => {
|
|
8153
|
+
const conn = connectionRef.current;
|
|
8154
|
+
if (!conn) throw new Error("Server connection not available");
|
|
8155
|
+
return await conn.readResource(uri);
|
|
8156
|
+
});
|
|
8157
|
+
bridge.onlistresources = (async () => {
|
|
8158
|
+
const conn = connectionRef.current;
|
|
8159
|
+
if (!conn) throw new Error("Server connection not available");
|
|
8160
|
+
return { resources: [...conn.resources ?? []] };
|
|
8161
|
+
});
|
|
8162
|
+
}
|
|
7795
8163
|
bridge.onrequestdisplaymode = async ({
|
|
7796
8164
|
mode
|
|
7797
8165
|
}) => {
|
|
7798
8166
|
const requested = mode ?? "inline";
|
|
7799
|
-
const
|
|
7800
|
-
|
|
7801
|
-
|
|
7802
|
-
|
|
7803
|
-
|
|
7804
|
-
|
|
8167
|
+
const effective = resolveRequestedDisplayMode({
|
|
8168
|
+
requested,
|
|
8169
|
+
current: displayModeRef.current,
|
|
8170
|
+
hostAvailable: hostContextRef.current?.availableDisplayModes,
|
|
8171
|
+
appAvailable: bridge?.getAppCapabilities()?.availableDisplayModes
|
|
8172
|
+
});
|
|
7805
8173
|
await handleDisplayModeChangeRef.current(effective);
|
|
7806
8174
|
return { mode: effective };
|
|
7807
8175
|
};
|
|
7808
|
-
|
|
7809
|
-
|
|
7810
|
-
|
|
7811
|
-
|
|
7812
|
-
|
|
7813
|
-
|
|
7814
|
-
|
|
7815
|
-
|
|
7816
|
-
|
|
7817
|
-
|
|
7818
|
-
|
|
7819
|
-
|
|
7820
|
-
|
|
7821
|
-
|
|
8176
|
+
if (capabilities.updateModelContext) {
|
|
8177
|
+
bridge.onupdatemodelcontext = async ({
|
|
8178
|
+
content,
|
|
8179
|
+
structuredContent
|
|
8180
|
+
}) => {
|
|
8181
|
+
if (!onModelContextUpdateRef.current) {
|
|
8182
|
+
throw new Error(
|
|
8183
|
+
"This host surface does not support model context updates"
|
|
8184
|
+
);
|
|
8185
|
+
}
|
|
8186
|
+
await onModelContextUpdateRef.current({
|
|
8187
|
+
content,
|
|
8188
|
+
structuredContent
|
|
8189
|
+
});
|
|
8190
|
+
return {};
|
|
8191
|
+
};
|
|
8192
|
+
}
|
|
8193
|
+
if (capabilities.logging) {
|
|
8194
|
+
bridge.onloggingmessage = async ({
|
|
8195
|
+
level,
|
|
8196
|
+
data
|
|
8197
|
+
}) => {
|
|
8198
|
+
onLogRef.current?.({ level, data });
|
|
8199
|
+
return {};
|
|
8200
|
+
};
|
|
8201
|
+
}
|
|
7822
8202
|
bridge.onsizechange = async ({
|
|
7823
8203
|
height
|
|
7824
8204
|
}) => {
|
|
@@ -7904,7 +8284,7 @@ function ViewRendererBase({
|
|
|
7904
8284
|
resolved,
|
|
7905
8285
|
activeSandboxUrl,
|
|
7906
8286
|
hostInfo,
|
|
7907
|
-
|
|
8287
|
+
effectiveHostCapabilities,
|
|
7908
8288
|
cspMode,
|
|
7909
8289
|
viewId,
|
|
7910
8290
|
wrapTransport,
|
|
@@ -8070,6 +8450,11 @@ function viewRendererAreEqual(prev, next) {
|
|
|
8070
8450
|
if (prev.customProps !== next.customProps) return false;
|
|
8071
8451
|
if (prev.hostContext !== next.hostContext) return false;
|
|
8072
8452
|
if (prev.hostCapabilities !== next.hostCapabilities) return false;
|
|
8453
|
+
if (prev.messageCapabilities !== next.messageCapabilities) return false;
|
|
8454
|
+
if (prev.modelContextCapabilities !== next.modelContextCapabilities)
|
|
8455
|
+
return false;
|
|
8456
|
+
if (prev.onMessage !== next.onMessage) return false;
|
|
8457
|
+
if (prev.onModelContextUpdate !== next.onModelContextUpdate) return false;
|
|
8073
8458
|
if (prev.cspMode !== next.cspMode) return false;
|
|
8074
8459
|
if (prev.mockOpenAiFileApis !== next.mockOpenAiFileApis) return false;
|
|
8075
8460
|
if (prev.onInlineHeightChange !== next.onInlineHeightChange) return false;
|
|
@@ -8094,14 +8479,17 @@ export {
|
|
|
8094
8479
|
getAllRpcLogs,
|
|
8095
8480
|
getRpcLogs,
|
|
8096
8481
|
getViewResourceUri,
|
|
8482
|
+
isToolVisibleToModel,
|
|
8097
8483
|
isViewResource,
|
|
8098
8484
|
isViewTool,
|
|
8099
8485
|
onMcpAuthorization,
|
|
8100
8486
|
parseCustomProps,
|
|
8487
|
+
pickPersistedServerConfig,
|
|
8101
8488
|
resolveViewResource,
|
|
8102
8489
|
setTelemetrySource,
|
|
8103
8490
|
specTypeSchemas,
|
|
8104
8491
|
subscribeToRpcLogs,
|
|
8492
|
+
toPersistedServerConfig,
|
|
8105
8493
|
useMcp,
|
|
8106
8494
|
useMcpClient,
|
|
8107
8495
|
useMcpServer
|