@assistant-ui/react-mcp 0.1.21 → 0.1.22
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/auth/createOAuthProvider.d.ts.map +1 -1
- package/dist/auth/createOAuthProvider.js +7 -1
- package/dist/auth/createOAuthProvider.js.map +1 -1
- package/dist/primitives/addForm/McpAddFormRoot.d.ts.map +1 -1
- package/dist/primitives/addForm/McpAddFormRoot.js +14 -5
- package/dist/primitives/addForm/McpAddFormRoot.js.map +1 -1
- package/dist/resources/McpCustomServerPersistence.d.ts +17 -0
- package/dist/resources/McpCustomServerPersistence.d.ts.map +1 -0
- package/dist/resources/McpCustomServerPersistence.js +192 -0
- package/dist/resources/McpCustomServerPersistence.js.map +1 -0
- package/dist/resources/McpElicitationLifecycle.d.ts +12 -0
- package/dist/resources/McpElicitationLifecycle.d.ts.map +1 -0
- package/dist/resources/McpElicitationLifecycle.js +144 -0
- package/dist/resources/McpElicitationLifecycle.js.map +1 -0
- package/dist/resources/McpManagerResource.d.ts.map +1 -1
- package/dist/resources/McpManagerResource.js +28 -205
- package/dist/resources/McpManagerResource.js.map +1 -1
- package/dist/resources/McpServerResource.d.ts.map +1 -1
- package/dist/resources/McpServerResource.js +24 -101
- package/dist/resources/McpServerResource.js.map +1 -1
- package/dist/resources/storage/McpLocalStorage.d.ts +1 -4
- package/dist/resources/storage/McpLocalStorage.d.ts.map +1 -1
- package/dist/resources/storage/McpLocalStorage.js +1 -100
- package/dist/resources/storage/McpLocalStorage.js.map +1 -1
- package/dist/resources/storage/McpStoredDataNormalization.d.ts +5 -0
- package/dist/resources/storage/McpStoredDataNormalization.d.ts.map +1 -0
- package/dist/resources/storage/McpStoredDataNormalization.js +95 -0
- package/dist/resources/storage/McpStoredDataNormalization.js.map +1 -0
- package/dist/utils/serverUrl.d.ts +1 -0
- package/dist/utils/serverUrl.d.ts.map +1 -1
- package/dist/utils/serverUrl.js +15 -1
- package/dist/utils/serverUrl.js.map +1 -1
- package/package.json +10 -9
- package/src/auth/createOAuthProvider.test.ts +30 -1
- package/src/auth/createOAuthProvider.ts +12 -4
- package/src/primitives/addForm/McpAddFormRoot.test.tsx +66 -0
- package/src/primitives/addForm/McpAddFormRoot.tsx +11 -1
- package/src/resources/McpCustomServerPersistence.test.ts +56 -0
- package/src/resources/McpCustomServerPersistence.ts +233 -0
- package/src/resources/McpElicitationLifecycle.test.ts +83 -0
- package/src/resources/McpElicitationLifecycle.ts +156 -0
- package/src/resources/McpManagerResource.test.ts +36 -0
- package/src/resources/McpManagerResource.ts +25 -248
- package/src/resources/McpServerResource.test.ts +123 -10
- package/src/resources/McpServerResource.ts +29 -149
- package/src/resources/storage/McpLocalStorage.ts +9 -209
- package/src/resources/storage/McpStoredDataNormalization.test.ts +24 -0
- package/src/resources/storage/McpStoredDataNormalization.ts +201 -0
- package/src/utils/serverUrl.test.ts +30 -0
- package/src/utils/serverUrl.ts +26 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createOAuthProvider.d.ts","sourceRoot":"","sources":["../../src/auth/createOAuthProvider.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,mBAAmB,EACnB,0BAA0B,EAG1B,WAAW,EACZ,MAAM,8BAA8B,CAAC;AACtC,OAAO,KAAK,EAAE,UAAU,EAAE,sCAAmC;AAC7D,OAAO,KAAK,EAAE,aAAa,EAAE,wBAAqB;
|
|
1
|
+
{"version":3,"file":"createOAuthProvider.d.ts","sourceRoot":"","sources":["../../src/auth/createOAuthProvider.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,mBAAmB,EACnB,0BAA0B,EAG1B,WAAW,EACZ,MAAM,8BAA8B,CAAC;AACtC,OAAO,KAAK,EAAE,UAAU,EAAE,sCAAmC;AAC7D,OAAO,KAAK,EAAE,aAAa,EAAE,wBAAqB;AAyClD,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAcpE;AAED,MAAM,MAAM,0BAA0B,GAAG;IACvC,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,uCAAuC;IACvC,MAAM,EAAE,OAAO,CAAC,aAAa,EAAE;QAAE,IAAI,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IAClD,OAAO,EAAE,UAAU,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,6DAA6D;IAC7D,kBAAkB,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,IAAI,CAAC;CACxC,CAAC;AAaF,KAAK,WAAW,GAAG,OAAO,CAAC,aAAa,EAAE;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,CAAC,CAAC;AAE7D,KAAK,oBAAoB,GAAG;IAC1B,MAAM,CAAC,EAAE,WAAW,GAAG,SAAS,CAAC;IACjC,cAAc,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,iBAAiB,CAAC,EAAE,0BAA0B,GAAG,SAAS,CAAC;IAC3D,uBAAuB,CAAC,EAAE,YAAY,GAAG,SAAS,CAAC;CACpD,CAAC;AASF,eAAO,MAAM,oBAAoB,GAC/B,OAAO,oBAAoB,GAAG,IAAI,GAAG,SAAS,EAC9C,QAAQ,WAAW,KAClB,OAOF,CAAC;AAqGF;;;;GAIG;AACH,eAAO,MAAM,2BAA2B,GACtC,SAAS,UAAU,EACnB,UAAU,MAAM,KACf,OAAO,CAAC,IAAI,CAoBd,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,0BAA0B,GAC/B,mBAAmB,CAqOrB"}
|
|
@@ -17,6 +17,12 @@ function encodeServerIdInState(serverId) {
|
|
|
17
17
|
const bytes = new TextEncoder().encode(serverId);
|
|
18
18
|
return `${STATE_PREFIX}${bytesToBase64Url(bytes)}`;
|
|
19
19
|
}
|
|
20
|
+
function createStateNonce() {
|
|
21
|
+
if (typeof crypto === "undefined") throw new Error("Web Crypto is required to start MCP OAuth");
|
|
22
|
+
if (typeof crypto.randomUUID === "function") return crypto.randomUUID();
|
|
23
|
+
if (typeof crypto.getRandomValues !== "function") throw new Error("Web Crypto is required to start MCP OAuth");
|
|
24
|
+
return bytesToBase64Url(crypto.getRandomValues(/* @__PURE__ */ new Uint8Array(32)));
|
|
25
|
+
}
|
|
20
26
|
function decodeServerIdFromState(state) {
|
|
21
27
|
if (!state.startsWith(STATE_PREFIX)) return null;
|
|
22
28
|
const dot = state.indexOf(".", 8);
|
|
@@ -202,7 +208,7 @@ function createOAuthProvider(opts) {
|
|
|
202
208
|
return clientMetadata;
|
|
203
209
|
},
|
|
204
210
|
state() {
|
|
205
|
-
const nonce =
|
|
211
|
+
const nonce = createStateNonce();
|
|
206
212
|
pendingState = `${encodeServerIdInState(serverId)}.${nonce}`;
|
|
207
213
|
return pendingState;
|
|
208
214
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createOAuthProvider.js","names":["OAuthClientProvider","OAuthClientInformationFull","OAuthClientMetadata","OAuthDiscoveryState","OAuthTokens","MCPStorage","MCPAuthConfig","MCPPersistedAuthState","isAuthStateForServerUrl","normalizeMcpServerUrl","STATE_PREFIX","bytesToBase64Url","bytes","Uint8Array","s","b","String","fromCharCode","btoa","replace","base64UrlToBytes","b64url","padded","repeat","length","bin","atob","out","i","charCodeAt","encodeServerIdInState","serverId","TextEncoder","encode","decodeServerIdFromState","state","startsWith","dot","indexOf","encoded","slice","TextDecoder","fatal","decode","CreateOAuthProviderOptions","serverUrl","config","Extract","type","storage","redirectUri","onAuthorizationUrl","url","URL","OAuthProviderCache","token","tokens","tokensClientId","clientInformation","clientInformationSource","codeVerifier","discoveryState","OAuthConfig","OAuthCredentialState","registeredClientId","client_id","undefined","hasUsableOAuthTokens","clientId","hasUsableRegisteredClientInformation","OAuthProviderEndpointCache","cached","cachePromise","Promise","invalidated","OAuthProviderPersistence","endpoint","queue","anchorByStorage","WeakMap","anchorByScope","Map","WeakRef","anchorRegistry","FinalizationRegistry","scopeId","get","deref","delete","getStorageIdentity","existing","anchor","set","register","persistenceByIdentity","getPersistence","persistence","identity","byServerId","resolve","clearOAuthProviderAuthState","clearAuthState","size","allSettled","createOAuthProvider","opts","normalizedServerUrl","pendingState","configuredClientInformation","ci","redirect_uris","clientSecret","client_secret","clientInformationOverlay","activeClientId","cache","loadCache","then","loadAuthState","persisted","initial","needsMigration","persist","catch","error","task","c","next","Parameters","saveAuthState","clientMetadata","client_name","grant_types","response_types","token_endpoint_auth_method","scope","scopes","join","redirectUrl","nonce","crypto","randomUUID","Date","now","Math","random","saveClientInformation","info","saveTokens","redirectToAuthorization","saveCodeVerifier","Error","saveDiscoveryState","invalidateCredentials"],"sources":["../../src/auth/createOAuthProvider.ts"],"sourcesContent":["import type {\n OAuthClientProvider,\n OAuthClientInformationFull,\n OAuthClientMetadata,\n OAuthDiscoveryState,\n OAuthTokens,\n} from \"@modelcontextprotocol/client\";\nimport type { MCPStorage } from \"../resources/storage/types\";\nimport type { MCPAuthConfig } from \"../mcp-scope\";\nimport type { MCPPersistedAuthState } from \"./types\";\nimport {\n isAuthStateForServerUrl,\n normalizeMcpServerUrl,\n} from \"../utils/serverUrl\";\n\nconst STATE_PREFIX = \"aui-mcp:\";\n\nfunction bytesToBase64Url(bytes: Uint8Array): string {\n let s = \"\";\n for (const b of bytes) s += String.fromCharCode(b);\n return btoa(s).replace(/\\+/g, \"-\").replace(/\\//g, \"_\").replace(/=+$/, \"\");\n}\n\nfunction base64UrlToBytes(b64url: string): Uint8Array {\n const padded =\n b64url.replace(/-/g, \"+\").replace(/_/g, \"/\") +\n \"=\".repeat((4 - (b64url.length % 4)) % 4);\n const bin = atob(padded);\n const out = new Uint8Array(bin.length);\n for (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i);\n return out;\n}\n\nfunction encodeServerIdInState(serverId: string): string {\n const bytes = new TextEncoder().encode(serverId);\n return `${STATE_PREFIX}${bytesToBase64Url(bytes)}`;\n}\n\nexport function decodeServerIdFromState(state: string): string | null {\n if (!state.startsWith(STATE_PREFIX)) return null;\n const dot = state.indexOf(\".\", STATE_PREFIX.length);\n const encoded =\n dot === -1\n ? state.slice(STATE_PREFIX.length)\n : state.slice(STATE_PREFIX.length, dot);\n try {\n return new TextDecoder(\"utf-8\", { fatal: true }).decode(\n base64UrlToBytes(encoded),\n );\n } catch {\n return null;\n }\n}\n\nexport type CreateOAuthProviderOptions = {\n serverId: string;\n serverUrl: string;\n /** Must be `auth.type === \"oauth\"`. */\n config: Extract<MCPAuthConfig, { type: \"oauth\" }>;\n storage: MCPStorage;\n redirectUri: string;\n /** Called by the SDK to start the authorization redirect. */\n onAuthorizationUrl: (url: URL) => void;\n};\n\ntype OAuthProviderCache = {\n token?: string | undefined;\n tokens?: OAuthTokens | undefined;\n tokensClientId?: string | undefined;\n clientInformation?: OAuthClientInformationFull | undefined;\n clientInformationSource?: MCPPersistedAuthState[\"clientInformationSource\"];\n codeVerifier?: string | undefined;\n state?: string | undefined;\n discoveryState?: OAuthDiscoveryState | undefined;\n};\n\ntype OAuthConfig = Extract<MCPAuthConfig, { type: \"oauth\" }>;\n\ntype OAuthCredentialState = {\n tokens?: OAuthTokens | undefined;\n tokensClientId?: string | undefined;\n clientInformation?: OAuthClientInformationFull | undefined;\n clientInformationSource?: \"registered\" | undefined;\n};\n\nconst registeredClientId = (\n state: OAuthCredentialState | null | undefined,\n): string | undefined =>\n state?.clientInformationSource === \"registered\"\n ? state.clientInformation?.client_id\n : undefined;\n\nexport const hasUsableOAuthTokens = (\n state: OAuthCredentialState | null | undefined,\n config: OAuthConfig,\n): boolean => {\n const clientId = config.clientId ?? registeredClientId(state);\n return (\n clientId !== undefined &&\n state?.tokens !== undefined &&\n state.tokensClientId === clientId\n );\n};\n\nconst hasUsableRegisteredClientInformation = (\n state: OAuthCredentialState | null | undefined,\n config: OAuthConfig,\n): boolean => {\n const clientId = registeredClientId(state);\n return (\n clientId !== undefined &&\n (config.clientId === undefined || config.clientId === clientId)\n );\n};\n\ntype OAuthProviderEndpointCache = {\n serverUrl: string;\n cached: OAuthProviderCache | null;\n cachePromise: Promise<OAuthProviderCache> | null;\n invalidated: boolean;\n};\n\ntype OAuthProviderPersistence = {\n endpoint: OAuthProviderEndpointCache | null;\n queue: Promise<void>;\n invalidated: boolean;\n};\n\n// scopeId, not object identity, is what addresses the same persisted data, so\n// storages sharing one share an anchor and an unscoped storage is its own\n// identity. Every storage declaring a scope holds that scope's anchor, so the\n// coordination state below is collected once the last of them is gone.\nconst anchorByStorage = new WeakMap<MCPStorage, object>();\nconst anchorByScope = new Map<string, WeakRef<object>>();\nconst anchorRegistry = new FinalizationRegistry<string>((scopeId) => {\n if (!anchorByScope.get(scopeId)?.deref()) anchorByScope.delete(scopeId);\n});\n\nconst getStorageIdentity = (storage: MCPStorage): object => {\n const existing = anchorByStorage.get(storage);\n if (existing) return existing;\n\n const { scopeId } = storage;\n if (scopeId === undefined) return storage;\n\n let anchor = anchorByScope.get(scopeId)?.deref();\n if (!anchor) {\n anchor = {};\n anchorByScope.set(scopeId, new WeakRef(anchor));\n anchorRegistry.register(anchor, scopeId);\n }\n anchorByStorage.set(storage, anchor);\n return anchor;\n};\n\n// McpServerResource builds a fresh provider for every transport, so the cache,\n// the in-flight load, and the write queue have to outlive any one provider.\n// saveAuthState replaces the whole record, so two providers writing their own\n// snapshots concurrently would drop whichever field the loser had added.\nconst persistenceByIdentity = new WeakMap<\n object,\n Map<string, OAuthProviderPersistence>\n>();\n\nconst getPersistence = (\n storage: MCPStorage,\n serverId: string,\n serverUrl: string,\n): {\n persistence: OAuthProviderPersistence;\n endpoint: OAuthProviderEndpointCache;\n} => {\n const identity = getStorageIdentity(storage);\n let byServerId = persistenceByIdentity.get(identity);\n if (!byServerId) {\n byServerId = new Map();\n persistenceByIdentity.set(identity, byServerId);\n }\n\n let persistence = byServerId.get(serverId);\n if (!persistence) {\n persistence = {\n endpoint: null,\n queue: Promise.resolve(),\n invalidated: false,\n };\n byServerId.set(serverId, persistence);\n }\n\n let endpoint = persistence.endpoint;\n if (endpoint?.serverUrl !== serverUrl) {\n if (endpoint) endpoint.invalidated = true;\n endpoint = {\n serverUrl,\n cached: null,\n cachePromise: null,\n invalidated: false,\n };\n persistence.endpoint = endpoint;\n }\n return { persistence, endpoint };\n};\n\n/**\n * Clears persisted OAuth state after the in-flight load and every queued write\n * for that server have settled, so a discarded provider cannot recreate the\n * record it was mid-save on.\n */\nexport const clearOAuthProviderAuthState = async (\n storage: MCPStorage,\n serverId: string,\n): Promise<void> => {\n const identity = getStorageIdentity(storage);\n const byServerId = persistenceByIdentity.get(identity);\n const persistence = byServerId?.get(serverId);\n if (!byServerId || !persistence) {\n await storage.clearAuthState(serverId);\n return;\n }\n\n // Detaching the entry before awaiting keeps a provider built during the clear\n // on a fresh generation instead of inheriting the fenced one.\n persistence.invalidated = true;\n byServerId.delete(serverId);\n if (byServerId.size === 0) persistenceByIdentity.delete(identity);\n\n if (persistence.endpoint) persistence.endpoint.invalidated = true;\n const cachePromise = persistence.endpoint?.cachePromise;\n if (cachePromise) await Promise.allSettled([cachePromise]);\n await persistence.queue;\n await storage.clearAuthState(serverId);\n};\n\n/**\n * Builds an OAuthClientProvider for the MCP SDK, backed by MCPStorage.\n * Token refresh and DCR are handled by the SDK; this provider only mediates\n * load/save and the redirect step.\n */\nexport function createOAuthProvider(\n opts: CreateOAuthProviderOptions,\n): OAuthClientProvider {\n const {\n serverId,\n serverUrl,\n config,\n storage,\n redirectUri,\n onAuthorizationUrl,\n } = opts;\n const normalizedServerUrl = normalizeMcpServerUrl(serverUrl);\n const { persistence, endpoint } = getPersistence(\n storage,\n serverId,\n normalizedServerUrl,\n );\n let pendingState: string | undefined;\n\n // The cache is shared with every other provider for this storage, server id,\n // and server URL, so a statically configured client stays a read-time overlay\n // owned by this provider. Writing it into the cache would leak this provider's\n // registration to a replacement built for a different, or absent, clientId.\n // The SDK's write-backs, its issuer stamp included, replace the overlay.\n const configuredClientInformation = ():\n | OAuthClientInformationFull\n | undefined => {\n if (!config.clientId) return undefined;\n const ci: OAuthClientInformationFull = {\n client_id: config.clientId,\n redirect_uris: [redirectUri],\n };\n if (config.clientSecret) ci.client_secret = config.clientSecret;\n return ci;\n };\n let clientInformationOverlay = configuredClientInformation();\n\n const activeClientId = (cache: OAuthProviderCache): string | undefined =>\n clientInformationOverlay?.client_id ?? registeredClientId(cache);\n\n const loadCache = (): Promise<OAuthProviderCache> => {\n if (endpoint.invalidated) return Promise.resolve({});\n if (endpoint.cached) return Promise.resolve(endpoint.cached);\n if (endpoint.cachePromise) return endpoint.cachePromise;\n\n endpoint.cachePromise = persistence.queue\n .then(() => storage.loadAuthState(serverId))\n .then(\n async (persisted) => {\n const initial: OAuthProviderCache = {};\n let needsMigration = false;\n if (endpoint.invalidated) return initial;\n if (\n persisted &&\n isAuthStateForServerUrl(persisted, normalizedServerUrl)\n ) {\n if (\n hasUsableRegisteredClientInformation(persisted, config) &&\n persisted.clientInformation\n ) {\n initial.clientInformation = persisted.clientInformation;\n initial.clientInformationSource = \"registered\";\n } else if (\n persisted?.clientInformation ||\n persisted?.clientInformationSource !== undefined\n ) {\n needsMigration = true;\n }\n if (hasUsableOAuthTokens(persisted, config)) {\n initial.tokens = persisted.tokens;\n initial.tokensClientId = persisted.tokensClientId;\n } else if (\n persisted?.tokens ||\n persisted?.tokensClientId !== undefined\n ) {\n needsMigration = true;\n }\n if (persisted?.token) initial.token = persisted.token;\n if (persisted?.codeVerifier)\n initial.codeVerifier = persisted.codeVerifier;\n if (persisted?.state) initial.state = persisted.state;\n if (persisted?.discoveryState)\n initial.discoveryState = persisted.discoveryState;\n }\n endpoint.cached = initial;\n if (needsMigration) await persist().catch(() => {});\n return initial;\n },\n (error) => {\n endpoint.cachePromise = null;\n throw error;\n },\n );\n return endpoint.cachePromise;\n };\n\n function persist() {\n const task = persistence.queue.then(async () => {\n if (persistence.invalidated || endpoint.invalidated) return;\n const c = endpoint.cached;\n if (!c) return;\n const next: Parameters<typeof storage.saveAuthState>[1] = {};\n if (hasUsableOAuthTokens(c, config) && c.tokens && c.tokensClientId) {\n next.tokens = c.tokens;\n next.tokensClientId = c.tokensClientId;\n }\n if (c.clientInformation && c.clientInformationSource === \"registered\") {\n next.clientInformation = c.clientInformation;\n next.clientInformationSource = \"registered\";\n }\n if (c.token) next.token = c.token;\n if (c.codeVerifier) next.codeVerifier = c.codeVerifier;\n if (c.state) next.state = c.state;\n if (c.discoveryState) next.discoveryState = c.discoveryState;\n next.serverUrl = normalizedServerUrl;\n await storage.saveAuthState(serverId, next);\n });\n persistence.queue = task.catch(() => {});\n return task;\n }\n\n const clientMetadata: OAuthClientMetadata = {\n client_name: \"assistant-ui\",\n redirect_uris: [redirectUri],\n grant_types: [\"authorization_code\", \"refresh_token\"],\n response_types: [\"code\"],\n token_endpoint_auth_method: \"none\",\n scope: config.scopes?.join(\" \"),\n };\n\n return {\n get redirectUrl() {\n return redirectUri;\n },\n get clientMetadata() {\n return clientMetadata;\n },\n state() {\n // Embed the server id so the callback handler can route it back to the\n // right MCPServerResource without app-level wiring.\n const nonce =\n typeof crypto !== \"undefined\" && \"randomUUID\" in crypto\n ? crypto.randomUUID()\n : `${Date.now()}.${Math.random()}`;\n pendingState = `${encodeServerIdInState(serverId)}.${nonce}`;\n return pendingState;\n },\n async clientInformation() {\n const c = await loadCache();\n if (clientInformationOverlay) return clientInformationOverlay;\n if (c.clientInformationSource !== \"registered\") return undefined;\n return c.clientInformation;\n },\n async saveClientInformation(info) {\n if (clientInformationOverlay) {\n clientInformationOverlay = info as OAuthClientInformationFull;\n return;\n }\n const c = await loadCache();\n c.clientInformation = info as OAuthClientInformationFull;\n c.clientInformationSource = \"registered\";\n if (c.tokensClientId !== c.clientInformation.client_id) {\n delete c.tokens;\n delete c.tokensClientId;\n }\n await persist();\n },\n async tokens() {\n const c = await loadCache();\n const clientId = activeClientId(c);\n if (clientId === undefined || c.tokensClientId !== clientId)\n return undefined;\n return c.tokens;\n },\n async saveTokens(tokens) {\n const c = await loadCache();\n c.tokens = tokens;\n const clientId = activeClientId(c);\n if (clientId) c.tokensClientId = clientId;\n else delete c.tokensClientId;\n delete c.state;\n await persist();\n },\n async redirectToAuthorization(url) {\n onAuthorizationUrl(url);\n },\n async saveCodeVerifier(codeVerifier) {\n const c = await loadCache();\n c.codeVerifier = codeVerifier;\n if (pendingState) {\n c.state = pendingState;\n pendingState = undefined;\n }\n await persist();\n },\n async codeVerifier() {\n const c = await loadCache();\n if (!c.codeVerifier) {\n throw new Error(\"No code verifier saved for this OAuth flow\");\n }\n return c.codeVerifier;\n },\n async saveDiscoveryState(discoveryState) {\n const c = await loadCache();\n c.discoveryState = discoveryState;\n await persist();\n },\n async discoveryState() {\n const c = await loadCache();\n return c.discoveryState;\n },\n async invalidateCredentials(scope) {\n const c = await loadCache();\n if (scope === \"all\" || scope === \"tokens\") {\n delete c.tokens;\n delete c.tokensClientId;\n }\n if (scope === \"all\" || scope === \"client\") {\n delete c.clientInformation;\n delete c.clientInformationSource;\n if (!config.clientId) {\n delete c.tokens;\n delete c.tokensClientId;\n }\n clientInformationOverlay = configuredClientInformation();\n }\n if (scope === \"all\" || scope === \"verifier\") {\n delete c.codeVerifier;\n delete c.state;\n }\n if (scope === \"all\" || scope === \"discovery\") delete c.discoveryState;\n await persist();\n },\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"createOAuthProvider.js","names":["OAuthClientProvider","OAuthClientInformationFull","OAuthClientMetadata","OAuthDiscoveryState","OAuthTokens","MCPStorage","MCPAuthConfig","MCPPersistedAuthState","isAuthStateForServerUrl","normalizeMcpServerUrl","STATE_PREFIX","bytesToBase64Url","bytes","Uint8Array","s","b","String","fromCharCode","btoa","replace","base64UrlToBytes","b64url","padded","repeat","length","bin","atob","out","i","charCodeAt","encodeServerIdInState","serverId","TextEncoder","encode","createStateNonce","crypto","Error","randomUUID","getRandomValues","decodeServerIdFromState","state","startsWith","dot","indexOf","encoded","slice","TextDecoder","fatal","decode","CreateOAuthProviderOptions","serverUrl","config","Extract","type","storage","redirectUri","onAuthorizationUrl","url","URL","OAuthProviderCache","token","tokens","tokensClientId","clientInformation","clientInformationSource","codeVerifier","discoveryState","OAuthConfig","OAuthCredentialState","registeredClientId","client_id","undefined","hasUsableOAuthTokens","clientId","hasUsableRegisteredClientInformation","OAuthProviderEndpointCache","cached","cachePromise","Promise","invalidated","OAuthProviderPersistence","endpoint","queue","anchorByStorage","WeakMap","anchorByScope","Map","WeakRef","anchorRegistry","FinalizationRegistry","scopeId","get","deref","delete","getStorageIdentity","existing","anchor","set","register","persistenceByIdentity","getPersistence","persistence","identity","byServerId","resolve","clearOAuthProviderAuthState","clearAuthState","size","allSettled","createOAuthProvider","opts","normalizedServerUrl","pendingState","configuredClientInformation","ci","redirect_uris","clientSecret","client_secret","clientInformationOverlay","activeClientId","cache","loadCache","then","loadAuthState","persisted","initial","needsMigration","persist","catch","error","task","c","next","Parameters","saveAuthState","clientMetadata","client_name","grant_types","response_types","token_endpoint_auth_method","scope","scopes","join","redirectUrl","nonce","saveClientInformation","info","saveTokens","redirectToAuthorization","saveCodeVerifier","saveDiscoveryState","invalidateCredentials"],"sources":["../../src/auth/createOAuthProvider.ts"],"sourcesContent":["import type {\n OAuthClientProvider,\n OAuthClientInformationFull,\n OAuthClientMetadata,\n OAuthDiscoveryState,\n OAuthTokens,\n} from \"@modelcontextprotocol/client\";\nimport type { MCPStorage } from \"../resources/storage/types\";\nimport type { MCPAuthConfig } from \"../mcp-scope\";\nimport type { MCPPersistedAuthState } from \"./types\";\nimport {\n isAuthStateForServerUrl,\n normalizeMcpServerUrl,\n} from \"../utils/serverUrl\";\n\nconst STATE_PREFIX = \"aui-mcp:\";\n\nfunction bytesToBase64Url(bytes: Uint8Array): string {\n let s = \"\";\n for (const b of bytes) s += String.fromCharCode(b);\n return btoa(s).replace(/\\+/g, \"-\").replace(/\\//g, \"_\").replace(/=+$/, \"\");\n}\n\nfunction base64UrlToBytes(b64url: string): Uint8Array {\n const padded =\n b64url.replace(/-/g, \"+\").replace(/_/g, \"/\") +\n \"=\".repeat((4 - (b64url.length % 4)) % 4);\n const bin = atob(padded);\n const out = new Uint8Array(bin.length);\n for (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i);\n return out;\n}\n\nfunction encodeServerIdInState(serverId: string): string {\n const bytes = new TextEncoder().encode(serverId);\n return `${STATE_PREFIX}${bytesToBase64Url(bytes)}`;\n}\n\nfunction createStateNonce(): string {\n if (typeof crypto === \"undefined\") {\n throw new Error(\"Web Crypto is required to start MCP OAuth\");\n }\n if (typeof crypto.randomUUID === \"function\") return crypto.randomUUID();\n if (typeof crypto.getRandomValues !== \"function\") {\n throw new Error(\"Web Crypto is required to start MCP OAuth\");\n }\n return bytesToBase64Url(crypto.getRandomValues(new Uint8Array(32)));\n}\n\nexport function decodeServerIdFromState(state: string): string | null {\n if (!state.startsWith(STATE_PREFIX)) return null;\n const dot = state.indexOf(\".\", STATE_PREFIX.length);\n const encoded =\n dot === -1\n ? state.slice(STATE_PREFIX.length)\n : state.slice(STATE_PREFIX.length, dot);\n try {\n return new TextDecoder(\"utf-8\", { fatal: true }).decode(\n base64UrlToBytes(encoded),\n );\n } catch {\n return null;\n }\n}\n\nexport type CreateOAuthProviderOptions = {\n serverId: string;\n serverUrl: string;\n /** Must be `auth.type === \"oauth\"`. */\n config: Extract<MCPAuthConfig, { type: \"oauth\" }>;\n storage: MCPStorage;\n redirectUri: string;\n /** Called by the SDK to start the authorization redirect. */\n onAuthorizationUrl: (url: URL) => void;\n};\n\ntype OAuthProviderCache = {\n token?: string | undefined;\n tokens?: OAuthTokens | undefined;\n tokensClientId?: string | undefined;\n clientInformation?: OAuthClientInformationFull | undefined;\n clientInformationSource?: MCPPersistedAuthState[\"clientInformationSource\"];\n codeVerifier?: string | undefined;\n state?: string | undefined;\n discoveryState?: OAuthDiscoveryState | undefined;\n};\n\ntype OAuthConfig = Extract<MCPAuthConfig, { type: \"oauth\" }>;\n\ntype OAuthCredentialState = {\n tokens?: OAuthTokens | undefined;\n tokensClientId?: string | undefined;\n clientInformation?: OAuthClientInformationFull | undefined;\n clientInformationSource?: \"registered\" | undefined;\n};\n\nconst registeredClientId = (\n state: OAuthCredentialState | null | undefined,\n): string | undefined =>\n state?.clientInformationSource === \"registered\"\n ? state.clientInformation?.client_id\n : undefined;\n\nexport const hasUsableOAuthTokens = (\n state: OAuthCredentialState | null | undefined,\n config: OAuthConfig,\n): boolean => {\n const clientId = config.clientId ?? registeredClientId(state);\n return (\n clientId !== undefined &&\n state?.tokens !== undefined &&\n state.tokensClientId === clientId\n );\n};\n\nconst hasUsableRegisteredClientInformation = (\n state: OAuthCredentialState | null | undefined,\n config: OAuthConfig,\n): boolean => {\n const clientId = registeredClientId(state);\n return (\n clientId !== undefined &&\n (config.clientId === undefined || config.clientId === clientId)\n );\n};\n\ntype OAuthProviderEndpointCache = {\n serverUrl: string;\n cached: OAuthProviderCache | null;\n cachePromise: Promise<OAuthProviderCache> | null;\n invalidated: boolean;\n};\n\ntype OAuthProviderPersistence = {\n endpoint: OAuthProviderEndpointCache | null;\n queue: Promise<void>;\n invalidated: boolean;\n};\n\n// scopeId, not object identity, is what addresses the same persisted data, so\n// storages sharing one share an anchor and an unscoped storage is its own\n// identity. Every storage declaring a scope holds that scope's anchor, so the\n// coordination state below is collected once the last of them is gone.\nconst anchorByStorage = new WeakMap<MCPStorage, object>();\nconst anchorByScope = new Map<string, WeakRef<object>>();\nconst anchorRegistry = new FinalizationRegistry<string>((scopeId) => {\n if (!anchorByScope.get(scopeId)?.deref()) anchorByScope.delete(scopeId);\n});\n\nconst getStorageIdentity = (storage: MCPStorage): object => {\n const existing = anchorByStorage.get(storage);\n if (existing) return existing;\n\n const { scopeId } = storage;\n if (scopeId === undefined) return storage;\n\n let anchor = anchorByScope.get(scopeId)?.deref();\n if (!anchor) {\n anchor = {};\n anchorByScope.set(scopeId, new WeakRef(anchor));\n anchorRegistry.register(anchor, scopeId);\n }\n anchorByStorage.set(storage, anchor);\n return anchor;\n};\n\n// McpServerResource builds a fresh provider for every transport, so the cache,\n// the in-flight load, and the write queue have to outlive any one provider.\n// saveAuthState replaces the whole record, so two providers writing their own\n// snapshots concurrently would drop whichever field the loser had added.\nconst persistenceByIdentity = new WeakMap<\n object,\n Map<string, OAuthProviderPersistence>\n>();\n\nconst getPersistence = (\n storage: MCPStorage,\n serverId: string,\n serverUrl: string,\n): {\n persistence: OAuthProviderPersistence;\n endpoint: OAuthProviderEndpointCache;\n} => {\n const identity = getStorageIdentity(storage);\n let byServerId = persistenceByIdentity.get(identity);\n if (!byServerId) {\n byServerId = new Map();\n persistenceByIdentity.set(identity, byServerId);\n }\n\n let persistence = byServerId.get(serverId);\n if (!persistence) {\n persistence = {\n endpoint: null,\n queue: Promise.resolve(),\n invalidated: false,\n };\n byServerId.set(serverId, persistence);\n }\n\n let endpoint = persistence.endpoint;\n if (endpoint?.serverUrl !== serverUrl) {\n if (endpoint) endpoint.invalidated = true;\n endpoint = {\n serverUrl,\n cached: null,\n cachePromise: null,\n invalidated: false,\n };\n persistence.endpoint = endpoint;\n }\n return { persistence, endpoint };\n};\n\n/**\n * Clears persisted OAuth state after the in-flight load and every queued write\n * for that server have settled, so a discarded provider cannot recreate the\n * record it was mid-save on.\n */\nexport const clearOAuthProviderAuthState = async (\n storage: MCPStorage,\n serverId: string,\n): Promise<void> => {\n const identity = getStorageIdentity(storage);\n const byServerId = persistenceByIdentity.get(identity);\n const persistence = byServerId?.get(serverId);\n if (!byServerId || !persistence) {\n await storage.clearAuthState(serverId);\n return;\n }\n\n // Detaching the entry before awaiting keeps a provider built during the clear\n // on a fresh generation instead of inheriting the fenced one.\n persistence.invalidated = true;\n byServerId.delete(serverId);\n if (byServerId.size === 0) persistenceByIdentity.delete(identity);\n\n if (persistence.endpoint) persistence.endpoint.invalidated = true;\n const cachePromise = persistence.endpoint?.cachePromise;\n if (cachePromise) await Promise.allSettled([cachePromise]);\n await persistence.queue;\n await storage.clearAuthState(serverId);\n};\n\n/**\n * Builds an OAuthClientProvider for the MCP SDK, backed by MCPStorage.\n * Token refresh and DCR are handled by the SDK; this provider only mediates\n * load/save and the redirect step.\n */\nexport function createOAuthProvider(\n opts: CreateOAuthProviderOptions,\n): OAuthClientProvider {\n const {\n serverId,\n serverUrl,\n config,\n storage,\n redirectUri,\n onAuthorizationUrl,\n } = opts;\n const normalizedServerUrl = normalizeMcpServerUrl(serverUrl);\n const { persistence, endpoint } = getPersistence(\n storage,\n serverId,\n normalizedServerUrl,\n );\n let pendingState: string | undefined;\n\n // The cache is shared with every other provider for this storage, server id,\n // and server URL, so a statically configured client stays a read-time overlay\n // owned by this provider. Writing it into the cache would leak this provider's\n // registration to a replacement built for a different, or absent, clientId.\n // The SDK's write-backs, its issuer stamp included, replace the overlay.\n const configuredClientInformation = ():\n | OAuthClientInformationFull\n | undefined => {\n if (!config.clientId) return undefined;\n const ci: OAuthClientInformationFull = {\n client_id: config.clientId,\n redirect_uris: [redirectUri],\n };\n if (config.clientSecret) ci.client_secret = config.clientSecret;\n return ci;\n };\n let clientInformationOverlay = configuredClientInformation();\n\n const activeClientId = (cache: OAuthProviderCache): string | undefined =>\n clientInformationOverlay?.client_id ?? registeredClientId(cache);\n\n const loadCache = (): Promise<OAuthProviderCache> => {\n if (endpoint.invalidated) return Promise.resolve({});\n if (endpoint.cached) return Promise.resolve(endpoint.cached);\n if (endpoint.cachePromise) return endpoint.cachePromise;\n\n endpoint.cachePromise = persistence.queue\n .then(() => storage.loadAuthState(serverId))\n .then(\n async (persisted) => {\n const initial: OAuthProviderCache = {};\n let needsMigration = false;\n if (endpoint.invalidated) return initial;\n if (\n persisted &&\n isAuthStateForServerUrl(persisted, normalizedServerUrl)\n ) {\n if (\n hasUsableRegisteredClientInformation(persisted, config) &&\n persisted.clientInformation\n ) {\n initial.clientInformation = persisted.clientInformation;\n initial.clientInformationSource = \"registered\";\n } else if (\n persisted?.clientInformation ||\n persisted?.clientInformationSource !== undefined\n ) {\n needsMigration = true;\n }\n if (hasUsableOAuthTokens(persisted, config)) {\n initial.tokens = persisted.tokens;\n initial.tokensClientId = persisted.tokensClientId;\n } else if (\n persisted?.tokens ||\n persisted?.tokensClientId !== undefined\n ) {\n needsMigration = true;\n }\n if (persisted?.token) initial.token = persisted.token;\n if (persisted?.codeVerifier)\n initial.codeVerifier = persisted.codeVerifier;\n if (persisted?.state) initial.state = persisted.state;\n if (persisted?.discoveryState)\n initial.discoveryState = persisted.discoveryState;\n }\n endpoint.cached = initial;\n if (needsMigration) await persist().catch(() => {});\n return initial;\n },\n (error) => {\n endpoint.cachePromise = null;\n throw error;\n },\n );\n return endpoint.cachePromise;\n };\n\n function persist() {\n const task = persistence.queue.then(async () => {\n if (persistence.invalidated || endpoint.invalidated) return;\n const c = endpoint.cached;\n if (!c) return;\n const next: Parameters<typeof storage.saveAuthState>[1] = {};\n if (hasUsableOAuthTokens(c, config) && c.tokens && c.tokensClientId) {\n next.tokens = c.tokens;\n next.tokensClientId = c.tokensClientId;\n }\n if (c.clientInformation && c.clientInformationSource === \"registered\") {\n next.clientInformation = c.clientInformation;\n next.clientInformationSource = \"registered\";\n }\n if (c.token) next.token = c.token;\n if (c.codeVerifier) next.codeVerifier = c.codeVerifier;\n if (c.state) next.state = c.state;\n if (c.discoveryState) next.discoveryState = c.discoveryState;\n next.serverUrl = normalizedServerUrl;\n await storage.saveAuthState(serverId, next);\n });\n persistence.queue = task.catch(() => {});\n return task;\n }\n\n const clientMetadata: OAuthClientMetadata = {\n client_name: \"assistant-ui\",\n redirect_uris: [redirectUri],\n grant_types: [\"authorization_code\", \"refresh_token\"],\n response_types: [\"code\"],\n token_endpoint_auth_method: \"none\",\n scope: config.scopes?.join(\" \"),\n };\n\n return {\n get redirectUrl() {\n return redirectUri;\n },\n get clientMetadata() {\n return clientMetadata;\n },\n state() {\n // Embed the server id so the callback handler can route it back to the\n // right MCPServerResource without app-level wiring.\n const nonce = createStateNonce();\n pendingState = `${encodeServerIdInState(serverId)}.${nonce}`;\n return pendingState;\n },\n async clientInformation() {\n const c = await loadCache();\n if (clientInformationOverlay) return clientInformationOverlay;\n if (c.clientInformationSource !== \"registered\") return undefined;\n return c.clientInformation;\n },\n async saveClientInformation(info) {\n if (clientInformationOverlay) {\n clientInformationOverlay = info as OAuthClientInformationFull;\n return;\n }\n const c = await loadCache();\n c.clientInformation = info as OAuthClientInformationFull;\n c.clientInformationSource = \"registered\";\n if (c.tokensClientId !== c.clientInformation.client_id) {\n delete c.tokens;\n delete c.tokensClientId;\n }\n await persist();\n },\n async tokens() {\n const c = await loadCache();\n const clientId = activeClientId(c);\n if (clientId === undefined || c.tokensClientId !== clientId)\n return undefined;\n return c.tokens;\n },\n async saveTokens(tokens) {\n const c = await loadCache();\n c.tokens = tokens;\n const clientId = activeClientId(c);\n if (clientId) c.tokensClientId = clientId;\n else delete c.tokensClientId;\n delete c.state;\n await persist();\n },\n async redirectToAuthorization(url) {\n onAuthorizationUrl(url);\n },\n async saveCodeVerifier(codeVerifier) {\n const c = await loadCache();\n c.codeVerifier = codeVerifier;\n if (pendingState) {\n c.state = pendingState;\n pendingState = undefined;\n }\n await persist();\n },\n async codeVerifier() {\n const c = await loadCache();\n if (!c.codeVerifier) {\n throw new Error(\"No code verifier saved for this OAuth flow\");\n }\n return c.codeVerifier;\n },\n async saveDiscoveryState(discoveryState) {\n const c = await loadCache();\n c.discoveryState = discoveryState;\n await persist();\n },\n async discoveryState() {\n const c = await loadCache();\n return c.discoveryState;\n },\n async invalidateCredentials(scope) {\n const c = await loadCache();\n if (scope === \"all\" || scope === \"tokens\") {\n delete c.tokens;\n delete c.tokensClientId;\n }\n if (scope === \"all\" || scope === \"client\") {\n delete c.clientInformation;\n delete c.clientInformationSource;\n if (!config.clientId) {\n delete c.tokens;\n delete c.tokensClientId;\n }\n clientInformationOverlay = configuredClientInformation();\n }\n if (scope === \"all\" || scope === \"verifier\") {\n delete c.codeVerifier;\n delete c.state;\n }\n if (scope === \"all\" || scope === \"discovery\") delete c.discoveryState;\n await persist();\n },\n };\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"McpAddFormRoot.d.ts","sourceRoot":"","sources":["../../../src/primitives/addForm/McpAddFormRoot.tsx"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,wBAAwB,EAC7B,KAAK,YAAY,EAOlB,MAAM,OAAO,CAAC;AACf,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"McpAddFormRoot.d.ts","sourceRoot":"","sources":["../../../src/primitives/addForm/McpAddFormRoot.tsx"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,wBAAwB,EAC7B,KAAK,YAAY,EAOlB,MAAM,OAAO,CAAC;AACf,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAqCtD,yBAAiB,uBAAuB,CAAC;IACvC,KAAY,OAAO,GAAG,YAAY,CAAC,OAAO,SAAS,CAAC,IAAI,CAAC,CAAC;IAC1D,KAAY,KAAK,GAAG,IAAI,CACtB,wBAAwB,CAAC,OAAO,SAAS,CAAC,IAAI,CAAC,EAC/C,UAAU,CACX,GAAG;QACF,WAAW,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;QACnC,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;KACvB,CAAC;CACH;AAED,eAAO,MAAM,uBAAuB;;;kBALlB,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI;eACvB,MAAM,IAAI;mDA0IvB,CAAC"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isSecureNetworkUrl } from "../../utils/serverUrl.js";
|
|
1
2
|
import { invokeMcpCallback } from "../../utils/invokeMcpCallback.js";
|
|
2
3
|
import { AddFormContext } from "./context.js";
|
|
3
4
|
import { useAui } from "@assistant-ui/store";
|
|
@@ -38,7 +39,7 @@ const McpAddFormPrimitiveRoot = forwardRef(({ onSubmitted, onCancel, ...props },
|
|
|
38
39
|
}), [formId]);
|
|
39
40
|
const setField = useCallback((key, value) => {
|
|
40
41
|
setState((prev) => {
|
|
41
|
-
const clearsError = prev.errorField === "form" || prev.errorField === key || key === "authType" && prev.errorField === "bearerToken";
|
|
42
|
+
const clearsError = prev.errorField === "form" || prev.errorField === key || key === "authType" && (prev.errorField === "bearerToken" || prev.errorField === "url");
|
|
42
43
|
return {
|
|
43
44
|
...prev,
|
|
44
45
|
[key]: value,
|
|
@@ -97,8 +98,16 @@ const McpAddFormPrimitiveRoot = forwardRef(({ onSubmitted, onCancel, ...props },
|
|
|
97
98
|
}));
|
|
98
99
|
return;
|
|
99
100
|
}
|
|
100
|
-
|
|
101
|
-
|
|
101
|
+
if (state.authType !== "none" && !isSecureNetworkUrl(urlResult.url)) {
|
|
102
|
+
setState((p_2) => ({
|
|
103
|
+
...p_2,
|
|
104
|
+
error: "Authenticated servers must use HTTPS or loopback HTTP",
|
|
105
|
+
errorField: "url"
|
|
106
|
+
}));
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
setState((p_3) => ({
|
|
110
|
+
...p_3,
|
|
102
111
|
submitting: true,
|
|
103
112
|
error: null,
|
|
104
113
|
errorField: null
|
|
@@ -112,8 +121,8 @@ const McpAddFormPrimitiveRoot = forwardRef(({ onSubmitted, onCancel, ...props },
|
|
|
112
121
|
setState(INITIAL);
|
|
113
122
|
invokeMcpCallback("onSubmitted", onSubmitted, id);
|
|
114
123
|
} catch (err) {
|
|
115
|
-
setState((
|
|
116
|
-
...
|
|
124
|
+
setState((p_4) => ({
|
|
125
|
+
...p_4,
|
|
117
126
|
submitting: false,
|
|
118
127
|
error: err instanceof Error ? err.message : String(err),
|
|
119
128
|
errorField: "form"
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"McpAddFormRoot.js","names":["ComponentPropsWithoutRef","ComponentRef","FormEventHandler","forwardRef","useCallback","useId","useMemo","useState","Primitive","useAui","AddFormContext","AddFormFieldIds","AddFormState","MCPAuthConfig","invokeMcpCallback","INITIAL","name","url","authType","bearerToken","scopes","submitting","error","errorField","validateUrl","raw","trimmed","trim","parsed","URL","protocol","McpAddFormPrimitiveRoot","Element","form","Props","Omit","onSubmitted","id","onCancel","props","ref","aui","formId","state","setState","ids","setField","key","K","value","prev","clearsError","reset","buildAuth","type","token","undefined","scopeList","split","map","s","filter","Boolean","length","submit","p","urlResult","mcp","addCustomServer","auth","err","Error","message","String","cancel","onFormSubmit","HTMLFormElement","e","preventDefault","displayName"],"sources":["../../../src/primitives/addForm/McpAddFormRoot.tsx"],"sourcesContent":["import {\n type ComponentPropsWithoutRef,\n type ComponentRef,\n type FormEventHandler,\n forwardRef,\n useCallback,\n useId,\n useMemo,\n useState,\n} from \"react\";\nimport { Primitive } from \"@radix-ui/react-primitive\";\nimport { useAui } from \"@assistant-ui/store\";\nimport {\n AddFormContext,\n type AddFormFieldIds,\n type AddFormState,\n} from \"./context\";\nimport type { MCPAuthConfig } from \"../../mcp-scope\";\nimport { invokeMcpCallback } from \"../../utils/invokeMcpCallback\";\n\nconst INITIAL: AddFormState = {\n name: \"\",\n url: \"\",\n authType: \"oauth\",\n bearerToken: \"\",\n scopes: \"\",\n submitting: false,\n error: null,\n errorField: null,\n};\n\nfunction validateUrl(raw: string): { url: string } | { error: string } {\n const trimmed = raw.trim();\n if (!trimmed) return { error: \"URL is required\" };\n let parsed: URL;\n try {\n parsed = new URL(trimmed);\n } catch {\n return { error: \"Invalid URL\" };\n }\n if (parsed.protocol !== \"http:\" && parsed.protocol !== \"https:\") {\n return { error: \"URL must be http(s)\" };\n }\n return { url: trimmed };\n}\n\nexport namespace McpAddFormPrimitiveRoot {\n export type Element = ComponentRef<typeof Primitive.form>;\n export type Props = Omit<\n ComponentPropsWithoutRef<typeof Primitive.form>,\n \"onSubmit\"\n > & {\n onSubmitted?: (id: string) => void;\n onCancel?: () => void;\n };\n}\n\nexport const McpAddFormPrimitiveRoot = forwardRef<\n McpAddFormPrimitiveRoot.Element,\n McpAddFormPrimitiveRoot.Props\n>(({ onSubmitted, onCancel, ...props }, ref) => {\n const aui = useAui();\n const formId = useId();\n const [state, setState] = useState<AddFormState>(INITIAL);\n const ids = useMemo<AddFormFieldIds>(\n () => ({\n bearerToken: `${formId}-bearer-token`,\n scopes: `${formId}-oauth-scopes`,\n error: `${formId}-error`,\n }),\n [formId],\n );\n\n const setField = useCallback(\n <K extends keyof AddFormState>(key: K, value: AddFormState[K]) => {\n setState((prev) => {\n const clearsError =\n prev.errorField === \"form\" ||\n prev.errorField === key ||\n (key === \"authType\"
|
|
1
|
+
{"version":3,"file":"McpAddFormRoot.js","names":["ComponentPropsWithoutRef","ComponentRef","FormEventHandler","forwardRef","useCallback","useId","useMemo","useState","Primitive","useAui","AddFormContext","AddFormFieldIds","AddFormState","MCPAuthConfig","invokeMcpCallback","isSecureNetworkUrl","INITIAL","name","url","authType","bearerToken","scopes","submitting","error","errorField","validateUrl","raw","trimmed","trim","parsed","URL","protocol","McpAddFormPrimitiveRoot","Element","form","Props","Omit","onSubmitted","id","onCancel","props","ref","aui","formId","state","setState","ids","setField","key","K","value","prev","clearsError","reset","buildAuth","type","token","undefined","scopeList","split","map","s","filter","Boolean","length","submit","p","urlResult","mcp","addCustomServer","auth","err","Error","message","String","cancel","onFormSubmit","HTMLFormElement","e","preventDefault","displayName"],"sources":["../../../src/primitives/addForm/McpAddFormRoot.tsx"],"sourcesContent":["import {\n type ComponentPropsWithoutRef,\n type ComponentRef,\n type FormEventHandler,\n forwardRef,\n useCallback,\n useId,\n useMemo,\n useState,\n} from \"react\";\nimport { Primitive } from \"@radix-ui/react-primitive\";\nimport { useAui } from \"@assistant-ui/store\";\nimport {\n AddFormContext,\n type AddFormFieldIds,\n type AddFormState,\n} from \"./context\";\nimport type { MCPAuthConfig } from \"../../mcp-scope\";\nimport { invokeMcpCallback } from \"../../utils/invokeMcpCallback\";\nimport { isSecureNetworkUrl } from \"../../utils/serverUrl\";\n\nconst INITIAL: AddFormState = {\n name: \"\",\n url: \"\",\n authType: \"oauth\",\n bearerToken: \"\",\n scopes: \"\",\n submitting: false,\n error: null,\n errorField: null,\n};\n\nfunction validateUrl(raw: string): { url: string } | { error: string } {\n const trimmed = raw.trim();\n if (!trimmed) return { error: \"URL is required\" };\n let parsed: URL;\n try {\n parsed = new URL(trimmed);\n } catch {\n return { error: \"Invalid URL\" };\n }\n if (parsed.protocol !== \"http:\" && parsed.protocol !== \"https:\") {\n return { error: \"URL must be http(s)\" };\n }\n return { url: trimmed };\n}\n\nexport namespace McpAddFormPrimitiveRoot {\n export type Element = ComponentRef<typeof Primitive.form>;\n export type Props = Omit<\n ComponentPropsWithoutRef<typeof Primitive.form>,\n \"onSubmit\"\n > & {\n onSubmitted?: (id: string) => void;\n onCancel?: () => void;\n };\n}\n\nexport const McpAddFormPrimitiveRoot = forwardRef<\n McpAddFormPrimitiveRoot.Element,\n McpAddFormPrimitiveRoot.Props\n>(({ onSubmitted, onCancel, ...props }, ref) => {\n const aui = useAui();\n const formId = useId();\n const [state, setState] = useState<AddFormState>(INITIAL);\n const ids = useMemo<AddFormFieldIds>(\n () => ({\n bearerToken: `${formId}-bearer-token`,\n scopes: `${formId}-oauth-scopes`,\n error: `${formId}-error`,\n }),\n [formId],\n );\n\n const setField = useCallback(\n <K extends keyof AddFormState>(key: K, value: AddFormState[K]) => {\n setState((prev) => {\n const clearsError =\n prev.errorField === \"form\" ||\n prev.errorField === key ||\n (key === \"authType\" &&\n (prev.errorField === \"bearerToken\" || prev.errorField === \"url\"));\n return {\n ...prev,\n [key]: value,\n ...(clearsError ? { error: null, errorField: null } : {}),\n };\n });\n },\n [],\n );\n\n const reset = useCallback(() => setState(INITIAL), []);\n\n const buildAuth = useCallback((): MCPAuthConfig => {\n switch (state.authType) {\n case \"none\":\n return { type: \"none\" };\n case \"bearer\":\n return { type: \"bearer\", token: state.bearerToken || undefined };\n case \"oauth\": {\n const scopeList = state.scopes\n .split(/[\\s,]+/)\n .map((s) => s.trim())\n .filter(Boolean);\n return {\n type: \"oauth\",\n scopes: scopeList.length > 0 ? scopeList : undefined,\n };\n }\n }\n }, [state.authType, state.bearerToken, state.scopes]);\n\n const submit = useCallback(async () => {\n if (state.submitting) return;\n if (!state.name.trim()) {\n setState((p) => ({\n ...p,\n error: \"Name is required\",\n errorField: \"name\",\n }));\n return;\n }\n if (state.authType === \"bearer\" && !state.bearerToken.trim()) {\n setState((p) => ({\n ...p,\n error: \"Bearer token is required\",\n errorField: \"bearerToken\",\n }));\n return;\n }\n const urlResult = validateUrl(state.url);\n if (\"error\" in urlResult) {\n setState((p) => ({\n ...p,\n error: urlResult.error,\n errorField: \"url\",\n }));\n return;\n }\n if (state.authType !== \"none\" && !isSecureNetworkUrl(urlResult.url)) {\n setState((p) => ({\n ...p,\n error: \"Authenticated servers must use HTTPS or loopback HTTP\",\n errorField: \"url\",\n }));\n return;\n }\n setState((p) => ({\n ...p,\n submitting: true,\n error: null,\n errorField: null,\n }));\n try {\n const id = await aui.mcp.addCustomServer({\n name: state.name.trim(),\n url: urlResult.url,\n auth: buildAuth(),\n });\n setState(INITIAL);\n invokeMcpCallback(\"onSubmitted\", onSubmitted, id);\n } catch (err) {\n setState((p) => ({\n ...p,\n submitting: false,\n error: err instanceof Error ? err.message : String(err),\n errorField: \"form\",\n }));\n }\n }, [aui, buildAuth, onSubmitted, state]);\n\n const cancel = useCallback(() => {\n setState(INITIAL);\n onCancel?.();\n }, [onCancel]);\n\n const value = useMemo(\n () => ({ state, ids, setField, reset, submit, cancel }),\n [state, ids, setField, reset, submit, cancel],\n );\n\n const onFormSubmit: FormEventHandler<HTMLFormElement> = (e) => {\n e.preventDefault();\n void submit();\n };\n\n return (\n <AddFormContext.Provider value={value}>\n <Primitive.form {...props} ref={ref} onSubmit={onFormSubmit} />\n </AddFormContext.Provider>\n );\n});\n\nMcpAddFormPrimitiveRoot.displayName = \"McpAddFormPrimitive.Root\";\n"],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { MCPCustomServerRecord } from "../mcp-scope.js";
|
|
2
|
+
import type { MCPStorage } from "./storage/types.js";
|
|
3
|
+
export type CustomServerPersistenceQueues = Map<string, Promise<void>>;
|
|
4
|
+
export declare const holdCustomServerPersistence: (persistenceQueues: CustomServerPersistenceQueues, scopeKey: string) => () => void;
|
|
5
|
+
type McpCustomServersResourceProps = {
|
|
6
|
+
storage: MCPStorage;
|
|
7
|
+
scopeKey: string;
|
|
8
|
+
persistenceQueues: CustomServerPersistenceQueues;
|
|
9
|
+
};
|
|
10
|
+
export declare const McpCustomServersResource: import("@assistant-ui/tap").Resource<{
|
|
11
|
+
customServers: MCPCustomServerRecord[];
|
|
12
|
+
isHydrated: boolean;
|
|
13
|
+
updateCustomServers: (updater: (records: MCPCustomServerRecord[]) => MCPCustomServerRecord[]) => void;
|
|
14
|
+
removeCustomServer: (id: string) => void;
|
|
15
|
+
}, [McpCustomServersResourceProps]>;
|
|
16
|
+
export {};
|
|
17
|
+
//# sourceMappingURL=McpCustomServerPersistence.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"McpCustomServerPersistence.d.ts","sourceRoot":"","sources":["../../src/resources/McpCustomServerPersistence.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,qBAAqB,EAAE,wBAAqB;AAC1D,OAAO,KAAK,EAAE,UAAU,EAAE,2BAAwB;AA6BlD,MAAM,MAAM,6BAA6B,GAAG,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;AA2BvE,eAAO,MAAM,2BAA2B,GACtC,mBAAmB,6BAA6B,EAChD,UAAU,MAAM,eAQjB,CAAC;AAgBF,KAAK,6BAA6B,GAAG;IACnC,OAAO,EAAE,UAAU,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,iBAAiB,EAAE,6BAA6B,CAAC;CAClD,CAAC;AAyIF,eAAO,MAAM,wBAAwB;;;mCA9CtB,CAAC,OAAO,EAAE,qBAAqB,EAAE,KAAK,qBAAqB,EAAE;6BA6BnE,MAAM;mCAiB8D,CAAC"}
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import { c } from "@assistant-ui/tap/react-shim/compiler-runtime";
|
|
2
|
+
import { useEffect, useEffectEvent, useRef, useState } from "@assistant-ui/tap/react-shim";
|
|
3
|
+
import { resource } from "@assistant-ui/tap";
|
|
4
|
+
//#region src/resources/McpCustomServerPersistence.ts
|
|
5
|
+
const reportCustomStorageFailure = (operation, error) => {
|
|
6
|
+
console.error(`[assistant-ui/react-mcp] failed to ${operation} custom servers:`, error);
|
|
7
|
+
};
|
|
8
|
+
const reportBlockedCustomServerPersistence = () => {
|
|
9
|
+
console.error("[assistant-ui/react-mcp] custom server changes remain in memory because loading the persisted list failed; remount the manager to retry");
|
|
10
|
+
};
|
|
11
|
+
const persistCustomServers = async (storage, records) => {
|
|
12
|
+
try {
|
|
13
|
+
await storage.saveCustomServers(records);
|
|
14
|
+
} catch (error) {
|
|
15
|
+
reportCustomStorageFailure("save", error);
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
const enqueueCustomServerTask = (persistenceQueues, scopeKey, task) => {
|
|
19
|
+
const next = (persistenceQueues.get(scopeKey) ?? Promise.resolve()).then(task);
|
|
20
|
+
persistenceQueues.set(scopeKey, next);
|
|
21
|
+
next.then(() => {
|
|
22
|
+
if (persistenceQueues.get(scopeKey) === next) persistenceQueues.delete(scopeKey);
|
|
23
|
+
});
|
|
24
|
+
};
|
|
25
|
+
const enqueueCustomServerPersistence = (persistenceQueues, scopeKey, storage, records) => enqueueCustomServerTask(persistenceQueues, scopeKey, () => persistCustomServers(storage, records));
|
|
26
|
+
const holdCustomServerPersistence = (persistenceQueues, scopeKey) => {
|
|
27
|
+
let release = () => {};
|
|
28
|
+
const gate = new Promise((resolve) => {
|
|
29
|
+
release = resolve;
|
|
30
|
+
});
|
|
31
|
+
enqueueCustomServerTask(persistenceQueues, scopeKey, () => gate);
|
|
32
|
+
return release;
|
|
33
|
+
};
|
|
34
|
+
const deduplicateCustomServers = (records) => {
|
|
35
|
+
const seen = /* @__PURE__ */ new Set();
|
|
36
|
+
return records.filter((record) => {
|
|
37
|
+
if (seen.has(record.id)) {
|
|
38
|
+
console.error(`[assistant-ui/react-mcp] ignored duplicate custom server id "${record.id}" loaded from storage`);
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
seen.add(record.id);
|
|
42
|
+
return true;
|
|
43
|
+
});
|
|
44
|
+
};
|
|
45
|
+
const useMcpCustomServersResource = (t0) => {
|
|
46
|
+
const $ = c(22);
|
|
47
|
+
const { storage, scopeKey, persistenceQueues } = t0;
|
|
48
|
+
let t1;
|
|
49
|
+
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
|
50
|
+
t1 = [];
|
|
51
|
+
$[0] = t1;
|
|
52
|
+
} else t1 = $[0];
|
|
53
|
+
const [customServers, setCustomServers] = useState(t1);
|
|
54
|
+
const [isHydrated, setIsHydrated] = useState(false);
|
|
55
|
+
let t2;
|
|
56
|
+
if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
|
|
57
|
+
t2 = [];
|
|
58
|
+
$[1] = t2;
|
|
59
|
+
} else t2 = $[1];
|
|
60
|
+
const customServersRef = useRef(t2);
|
|
61
|
+
const hydrationStateRef = useRef("pending");
|
|
62
|
+
const hasPendingMutationRef = useRef(false);
|
|
63
|
+
const [removedBeforeHydration] = useState(_temp);
|
|
64
|
+
const reportedBlockedPersistenceRef = useRef(false);
|
|
65
|
+
let t3;
|
|
66
|
+
if ($[2] !== persistenceQueues || $[3] !== removedBeforeHydration || $[4] !== scopeKey || $[5] !== storage) {
|
|
67
|
+
t3 = async (signal) => {
|
|
68
|
+
while (true) {
|
|
69
|
+
const pendingPersistence = persistenceQueues.get(scopeKey);
|
|
70
|
+
if (!pendingPersistence) break;
|
|
71
|
+
await pendingPersistence;
|
|
72
|
+
if (signal.cancelled) return;
|
|
73
|
+
if (persistenceQueues.get(scopeKey) === pendingPersistence) break;
|
|
74
|
+
}
|
|
75
|
+
let records;
|
|
76
|
+
try {
|
|
77
|
+
const loadedRecords = await storage.loadCustomServers();
|
|
78
|
+
records = deduplicateCustomServers(loadedRecords);
|
|
79
|
+
} catch (t4) {
|
|
80
|
+
const error = t4;
|
|
81
|
+
if (!signal.cancelled) {
|
|
82
|
+
reportCustomStorageFailure("load", error);
|
|
83
|
+
hydrationStateRef.current = "failed";
|
|
84
|
+
if (hasPendingMutationRef.current) {
|
|
85
|
+
reportBlockedCustomServerPersistence();
|
|
86
|
+
reportedBlockedPersistenceRef.current = true;
|
|
87
|
+
}
|
|
88
|
+
setIsHydrated(true);
|
|
89
|
+
}
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
const hadPendingMutation = hasPendingMutationRef.current;
|
|
93
|
+
const hydratedRecords = records.filter((record) => !removedBeforeHydration.has(record.id));
|
|
94
|
+
const mergedRecords = (() => {
|
|
95
|
+
const prev = customServersRef.current;
|
|
96
|
+
if (prev.length === 0) return hydratedRecords;
|
|
97
|
+
const persistedIds = new Set(hydratedRecords.map(_temp2));
|
|
98
|
+
return [...hydratedRecords, ...prev.filter((r_0) => !persistedIds.has(r_0.id))];
|
|
99
|
+
})();
|
|
100
|
+
customServersRef.current = mergedRecords;
|
|
101
|
+
hydrationStateRef.current = "succeeded";
|
|
102
|
+
hasPendingMutationRef.current = false;
|
|
103
|
+
if (hadPendingMutation) enqueueCustomServerPersistence(persistenceQueues, scopeKey, storage, mergedRecords);
|
|
104
|
+
if (signal.cancelled) return;
|
|
105
|
+
setCustomServers(mergedRecords);
|
|
106
|
+
setIsHydrated(true);
|
|
107
|
+
};
|
|
108
|
+
$[2] = persistenceQueues;
|
|
109
|
+
$[3] = removedBeforeHydration;
|
|
110
|
+
$[4] = scopeKey;
|
|
111
|
+
$[5] = storage;
|
|
112
|
+
$[6] = t3;
|
|
113
|
+
} else t3 = $[6];
|
|
114
|
+
const hydrate = useEffectEvent(t3);
|
|
115
|
+
let t4;
|
|
116
|
+
if ($[7] !== hydrate) {
|
|
117
|
+
t4 = () => {
|
|
118
|
+
const signal_0 = { cancelled: false };
|
|
119
|
+
hydrate(signal_0);
|
|
120
|
+
return () => {
|
|
121
|
+
signal_0.cancelled = true;
|
|
122
|
+
};
|
|
123
|
+
};
|
|
124
|
+
$[7] = hydrate;
|
|
125
|
+
$[8] = t4;
|
|
126
|
+
} else t4 = $[8];
|
|
127
|
+
let t5;
|
|
128
|
+
if ($[9] === Symbol.for("react.memo_cache_sentinel")) {
|
|
129
|
+
t5 = [];
|
|
130
|
+
$[9] = t5;
|
|
131
|
+
} else t5 = $[9];
|
|
132
|
+
useEffect(t4, t5);
|
|
133
|
+
let t6;
|
|
134
|
+
if ($[10] !== persistenceQueues || $[11] !== scopeKey || $[12] !== storage) {
|
|
135
|
+
t6 = (updater) => {
|
|
136
|
+
const next = updater(customServersRef.current);
|
|
137
|
+
customServersRef.current = next;
|
|
138
|
+
setCustomServers(next);
|
|
139
|
+
if (hydrationStateRef.current === "succeeded") {
|
|
140
|
+
enqueueCustomServerPersistence(persistenceQueues, scopeKey, storage, next);
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
hasPendingMutationRef.current = true;
|
|
144
|
+
if (hydrationStateRef.current === "failed" && !reportedBlockedPersistenceRef.current) {
|
|
145
|
+
reportBlockedCustomServerPersistence();
|
|
146
|
+
reportedBlockedPersistenceRef.current = true;
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
$[10] = persistenceQueues;
|
|
150
|
+
$[11] = scopeKey;
|
|
151
|
+
$[12] = storage;
|
|
152
|
+
$[13] = t6;
|
|
153
|
+
} else t6 = $[13];
|
|
154
|
+
const updateCustomServers = t6;
|
|
155
|
+
let t7;
|
|
156
|
+
if ($[14] !== removedBeforeHydration || $[15] !== updateCustomServers) {
|
|
157
|
+
t7 = (id) => {
|
|
158
|
+
if (hydrationStateRef.current === "pending") removedBeforeHydration.add(id);
|
|
159
|
+
updateCustomServers((prev_0) => prev_0.filter((record_0) => record_0.id !== id));
|
|
160
|
+
};
|
|
161
|
+
$[14] = removedBeforeHydration;
|
|
162
|
+
$[15] = updateCustomServers;
|
|
163
|
+
$[16] = t7;
|
|
164
|
+
} else t7 = $[16];
|
|
165
|
+
const removeCustomServer = t7;
|
|
166
|
+
let t8;
|
|
167
|
+
if ($[17] !== customServers || $[18] !== isHydrated || $[19] !== removeCustomServer || $[20] !== updateCustomServers) {
|
|
168
|
+
t8 = {
|
|
169
|
+
customServers,
|
|
170
|
+
isHydrated,
|
|
171
|
+
updateCustomServers,
|
|
172
|
+
removeCustomServer
|
|
173
|
+
};
|
|
174
|
+
$[17] = customServers;
|
|
175
|
+
$[18] = isHydrated;
|
|
176
|
+
$[19] = removeCustomServer;
|
|
177
|
+
$[20] = updateCustomServers;
|
|
178
|
+
$[21] = t8;
|
|
179
|
+
} else t8 = $[21];
|
|
180
|
+
return t8;
|
|
181
|
+
};
|
|
182
|
+
const McpCustomServersResource = resource(useMcpCustomServersResource);
|
|
183
|
+
function _temp() {
|
|
184
|
+
return /* @__PURE__ */ new Set();
|
|
185
|
+
}
|
|
186
|
+
function _temp2(r) {
|
|
187
|
+
return r.id;
|
|
188
|
+
}
|
|
189
|
+
//#endregion
|
|
190
|
+
export { McpCustomServersResource, holdCustomServerPersistence };
|
|
191
|
+
|
|
192
|
+
//# sourceMappingURL=McpCustomServerPersistence.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"McpCustomServerPersistence.js","names":["useState","useEffect","useEffectEvent","useRef","useCallback","resource","MCPCustomServerRecord","MCPStorage","reportCustomStorageFailure","operation","error","console","reportBlockedCustomServerPersistence","persistCustomServers","storage","records","saveCustomServers","CustomServerPersistenceQueues","Map","Promise","enqueueCustomServerTask","persistenceQueues","scopeKey","task","previous","get","next","resolve","then","set","delete","enqueueCustomServerPersistence","holdCustomServerPersistence","release","gate","deduplicateCustomServers","seen","Set","filter","record","has","id","add","McpCustomServersResourceProps","useMcpCustomServersResource","t0","$","_c","t1","Symbol","for","customServers","setCustomServers","isHydrated","setIsHydrated","t2","customServersRef","hydrationStateRef","hasPendingMutationRef","removedBeforeHydration","_temp","reportedBlockedPersistenceRef","t3","signal","pendingPersistence","cancelled","loadedRecords","loadCustomServers","t4","current","hadPendingMutation","hydratedRecords","mergedRecords","prev","length","persistedIds","map","_temp2","r_0","r","hydrate","signal_0","t5","t6","updater","updateCustomServers","t7","prev_0","record_0","removeCustomServer","t8","McpCustomServersResource","_c"],"sources":["../../src/resources/McpCustomServerPersistence.ts"],"sourcesContent":["import {\n useState,\n useEffect,\n useEffectEvent,\n useRef,\n useCallback,\n} from \"react\";\nimport { resource } from \"@assistant-ui/tap\";\nimport type { MCPCustomServerRecord } from \"../mcp-scope\";\nimport type { MCPStorage } from \"./storage/types\";\n\nconst reportCustomStorageFailure = (\n operation: \"load\" | \"save\",\n error: unknown,\n) => {\n console.error(\n `[assistant-ui/react-mcp] failed to ${operation} custom servers:`,\n error,\n );\n};\n\nconst reportBlockedCustomServerPersistence = () => {\n console.error(\n \"[assistant-ui/react-mcp] custom server changes remain in memory because loading the persisted list failed; remount the manager to retry\",\n );\n};\n\nconst persistCustomServers = async (\n storage: MCPStorage,\n records: MCPCustomServerRecord[],\n) => {\n try {\n await storage.saveCustomServers(records);\n } catch (error) {\n reportCustomStorageFailure(\"save\", error);\n }\n};\n\nexport type CustomServerPersistenceQueues = Map<string, Promise<void>>;\n\nconst enqueueCustomServerTask = (\n persistenceQueues: CustomServerPersistenceQueues,\n scopeKey: string,\n task: () => Promise<void>,\n) => {\n const previous = persistenceQueues.get(scopeKey);\n const next = (previous ?? Promise.resolve()).then(task);\n persistenceQueues.set(scopeKey, next);\n void next.then(() => {\n if (persistenceQueues.get(scopeKey) === next) {\n persistenceQueues.delete(scopeKey);\n }\n });\n};\n\nconst enqueueCustomServerPersistence = (\n persistenceQueues: CustomServerPersistenceQueues,\n scopeKey: string,\n storage: MCPStorage,\n records: MCPCustomServerRecord[],\n) =>\n enqueueCustomServerTask(persistenceQueues, scopeKey, () =>\n persistCustomServers(storage, records),\n );\n\nexport const holdCustomServerPersistence = (\n persistenceQueues: CustomServerPersistenceQueues,\n scopeKey: string,\n) => {\n let release = () => {};\n const gate = new Promise<void>((resolve) => {\n release = resolve;\n });\n enqueueCustomServerTask(persistenceQueues, scopeKey, () => gate);\n return release;\n};\n\nconst deduplicateCustomServers = (records: MCPCustomServerRecord[]) => {\n const seen = new Set<string>();\n return records.filter((record) => {\n if (seen.has(record.id)) {\n console.error(\n `[assistant-ui/react-mcp] ignored duplicate custom server id \"${record.id}\" loaded from storage`,\n );\n return false;\n }\n seen.add(record.id);\n return true;\n });\n};\n\ntype McpCustomServersResourceProps = {\n storage: MCPStorage;\n scopeKey: string;\n persistenceQueues: CustomServerPersistenceQueues;\n};\n\nconst useMcpCustomServersResource = ({\n storage,\n scopeKey,\n persistenceQueues,\n}: McpCustomServersResourceProps) => {\n const [customServers, setCustomServers] = useState<MCPCustomServerRecord[]>(\n [],\n );\n const [isHydrated, setIsHydrated] = useState(false);\n\n const customServersRef = useRef<MCPCustomServerRecord[]>([]);\n const hydrationStateRef = useRef<\"pending\" | \"succeeded\" | \"failed\">(\n \"pending\",\n );\n const hasPendingMutationRef = useRef(false);\n const [removedBeforeHydration] = useState(() => new Set<string>());\n const reportedBlockedPersistenceRef = useRef(false);\n\n const hydrate = useEffectEvent(async (signal: { cancelled: boolean }) => {\n // A revisited scope must not read behind writes still queued against it.\n while (true) {\n const pendingPersistence = persistenceQueues.get(scopeKey);\n if (!pendingPersistence) break;\n await pendingPersistence;\n if (signal.cancelled) return;\n if (persistenceQueues.get(scopeKey) === pendingPersistence) break;\n }\n\n let records: Awaited<ReturnType<typeof storage.loadCustomServers>>;\n try {\n const loadedRecords = await storage.loadCustomServers();\n records = deduplicateCustomServers(loadedRecords);\n } catch (error) {\n if (!signal.cancelled) {\n reportCustomStorageFailure(\"load\", error);\n hydrationStateRef.current = \"failed\";\n if (hasPendingMutationRef.current) {\n reportBlockedCustomServerPersistence();\n reportedBlockedPersistenceRef.current = true;\n }\n setIsHydrated(true);\n }\n return;\n }\n // Merge rather than replace so any addCustomServer calls that\n // happened before hydration resolved aren't silently overwritten.\n // Persisted order wins; pre-hydration locals append.\n const hadPendingMutation = hasPendingMutationRef.current;\n const hydratedRecords = records.filter(\n (record) => !removedBeforeHydration.has(record.id),\n );\n const mergedRecords = (() => {\n const prev = customServersRef.current;\n if (prev.length === 0) return hydratedRecords;\n const persistedIds = new Set(hydratedRecords.map((r) => r.id));\n return [\n ...hydratedRecords,\n ...prev.filter((r) => !persistedIds.has(r.id)),\n ];\n })();\n customServersRef.current = mergedRecords;\n hydrationStateRef.current = \"succeeded\";\n hasPendingMutationRef.current = false;\n if (hadPendingMutation) {\n enqueueCustomServerPersistence(\n persistenceQueues,\n scopeKey,\n storage,\n mergedRecords,\n );\n }\n if (signal.cancelled) return;\n setCustomServers(mergedRecords);\n setIsHydrated(true);\n });\n\n useEffect(() => {\n const signal = { cancelled: false };\n // Hydration reads persisted records asynchronously; there is no earlier\n // point than mount at which to start it.\n // eslint-disable-next-line react-hooks/set-state-in-effect\n void hydrate(signal);\n return () => {\n signal.cancelled = true;\n };\n }, []);\n\n const updateCustomServers = useCallback(\n (\n updater: (records: MCPCustomServerRecord[]) => MCPCustomServerRecord[],\n ) => {\n const next = updater(customServersRef.current);\n customServersRef.current = next;\n setCustomServers(next);\n\n if (hydrationStateRef.current === \"succeeded\") {\n enqueueCustomServerPersistence(\n persistenceQueues,\n scopeKey,\n storage,\n next,\n );\n return;\n }\n\n hasPendingMutationRef.current = true;\n if (\n hydrationStateRef.current === \"failed\" &&\n !reportedBlockedPersistenceRef.current\n ) {\n reportBlockedCustomServerPersistence();\n reportedBlockedPersistenceRef.current = true;\n }\n },\n [persistenceQueues, scopeKey, storage],\n );\n\n const removeCustomServer = useCallback(\n (id: string) => {\n if (hydrationStateRef.current === \"pending\") {\n removedBeforeHydration.add(id);\n }\n updateCustomServers((prev) => prev.filter((record) => record.id !== id));\n },\n [removedBeforeHydration, updateCustomServers],\n );\n\n return {\n customServers,\n isHydrated,\n updateCustomServers,\n removeCustomServer,\n };\n};\n\nexport const McpCustomServersResource = resource(useMcpCustomServersResource);\n"],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { ElicitRequest, ElicitResult } from "@modelcontextprotocol/client";
|
|
2
|
+
import type { MCPElicitation, MCPElicitationResponse } from "../mcp-scope.js";
|
|
3
|
+
export declare const useMcpElicitationLifecycle: () => {
|
|
4
|
+
pendingElicitations: MCPElicitation[];
|
|
5
|
+
cancelPendingElicitations: () => void;
|
|
6
|
+
requestElicitation: (request: ElicitRequest, signal: AbortSignal, isCurrentConnection: () => boolean) => Promise<ElicitResult>;
|
|
7
|
+
answerElicitation: (id: string, response: MCPElicitationResponse) => readonly {
|
|
8
|
+
property: string;
|
|
9
|
+
message: string;
|
|
10
|
+
}[] | undefined;
|
|
11
|
+
};
|
|
12
|
+
//# sourceMappingURL=McpElicitationLifecycle.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"McpElicitationLifecycle.d.ts","sourceRoot":"","sources":["../../src/resources/McpElicitationLifecycle.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAChF,OAAO,KAAK,EAAE,cAAc,EAAE,sBAAsB,EAAE,wBAAqB;AAI3E,eAAO,MAAM,0BAA0B;;;kCA+C1B,aAAa,UACd,WAAW,uBACE,MAAM,OAAO,KACjC,OAAO,CAAC,YAAY,CAAC;4BA+ChB,MAAM,YACA,sBAAsB,KAC/B,SAAS;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,EAAE,GAAG,SAAS;CAkDlE,CAAC"}
|