@assistant-ui/react-mcp 0.1.14 → 0.1.16

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.
Files changed (52) hide show
  1. package/dist/auth/createOAuthProvider.d.ts +7 -1
  2. package/dist/auth/createOAuthProvider.d.ts.map +1 -1
  3. package/dist/auth/createOAuthProvider.js +115 -31
  4. package/dist/auth/createOAuthProvider.js.map +1 -1
  5. package/dist/auth/types.d.ts +1 -0
  6. package/dist/auth/types.d.ts.map +1 -1
  7. package/dist/hooks/useMcpOAuthCallback.d.ts.map +1 -1
  8. package/dist/hooks/useMcpOAuthCallback.js +5 -6
  9. package/dist/hooks/useMcpOAuthCallback.js.map +1 -1
  10. package/dist/primitives/server/McpServerIcon.js.map +1 -1
  11. package/dist/primitives/server/McpServerOAuthLink.js.map +1 -1
  12. package/dist/resources/McpManagerResource.d.ts.map +1 -1
  13. package/dist/resources/McpManagerResource.js +4 -2
  14. package/dist/resources/McpManagerResource.js.map +1 -1
  15. package/dist/resources/McpServerResource.d.ts +2 -1
  16. package/dist/resources/McpServerResource.d.ts.map +1 -1
  17. package/dist/resources/McpServerResource.js +107 -21
  18. package/dist/resources/McpServerResource.js.map +1 -1
  19. package/dist/resources/storage/McpLocalStorage.d.ts +7 -0
  20. package/dist/resources/storage/McpLocalStorage.d.ts.map +1 -1
  21. package/dist/resources/storage/McpLocalStorage.js +132 -37
  22. package/dist/resources/storage/McpLocalStorage.js.map +1 -1
  23. package/dist/resources/storage/McpMemoryStorage.d.ts.map +1 -1
  24. package/dist/resources/storage/McpMemoryStorage.js +9 -6
  25. package/dist/resources/storage/McpMemoryStorage.js.map +1 -1
  26. package/dist/resources/storage/types.d.ts +12 -0
  27. package/dist/resources/storage/types.d.ts.map +1 -1
  28. package/dist/utils/createMcpId.d.ts +9 -0
  29. package/dist/utils/createMcpId.d.ts.map +1 -0
  30. package/dist/utils/createMcpId.js +11 -0
  31. package/dist/utils/createMcpId.js.map +1 -0
  32. package/dist/utils/invokeMcpCallback.d.ts.map +1 -1
  33. package/dist/utils/invokeMcpCallback.js +2 -12
  34. package/dist/utils/invokeMcpCallback.js.map +1 -1
  35. package/package.json +8 -8
  36. package/src/auth/createOAuthProvider.test.ts +407 -2
  37. package/src/auth/createOAuthProvider.ts +171 -40
  38. package/src/auth/types.ts +1 -0
  39. package/src/hooks/useMcpOAuthCallback.test.ts +74 -1
  40. package/src/hooks/useMcpOAuthCallback.tsx +11 -8
  41. package/src/resources/McpManagerResource.test.ts +128 -0
  42. package/src/resources/McpManagerResource.ts +4 -5
  43. package/src/resources/McpServerResource.test.ts +420 -18
  44. package/src/resources/McpServerResource.ts +148 -27
  45. package/src/resources/storage/McpLocalStorage.test.ts +71 -1
  46. package/src/resources/storage/McpLocalStorage.ts +69 -47
  47. package/src/resources/storage/McpMemoryStorage.test.ts +99 -0
  48. package/src/resources/storage/McpMemoryStorage.ts +23 -17
  49. package/src/resources/storage/types.ts +12 -0
  50. package/src/utils/createMcpId.test.ts +25 -0
  51. package/src/utils/createMcpId.ts +10 -0
  52. package/src/utils/invokeMcpCallback.ts +3 -21
@@ -14,6 +14,12 @@ type CreateOAuthProviderOptions = {
14
14
  /** Called by the SDK to start the authorization redirect. */
15
15
  onAuthorizationUrl: (url: URL) => void;
16
16
  };
17
+ /**
18
+ * Clears persisted OAuth state after the in-flight load and every queued write
19
+ * for that server have settled, so a discarded provider cannot recreate the
20
+ * record it was mid-save on.
21
+ */
22
+ declare const clearOAuthProviderAuthState: (storage: MCPStorage, serverId: string) => Promise<void>;
17
23
  /**
18
24
  * Builds an OAuthClientProvider for the MCP SDK, backed by MCPStorage.
19
25
  * Token refresh and DCR are handled by the SDK; this provider only mediates
@@ -21,5 +27,5 @@ type CreateOAuthProviderOptions = {
21
27
  */
22
28
  declare function createOAuthProvider(opts: CreateOAuthProviderOptions): OAuthClientProvider;
23
29
  //#endregion
24
- export { CreateOAuthProviderOptions, createOAuthProvider, decodeServerIdFromState };
30
+ export { CreateOAuthProviderOptions, clearOAuthProviderAuthState, createOAuthProvider, decodeServerIdFromState };
25
31
  //# sourceMappingURL=createOAuthProvider.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"createOAuthProvider.d.ts","names":[],"sources":["../../src/auth/createOAuthProvider.ts"],"mappings":";;;;iBAiCgB,wBAAwB;KAgB5B;EACV;;EAEA,QAAQ,QAAQ;IAAiB;;EACjC,SAAS;EACT;;EAEA,qBAAqB,KAAK;;;;;;;iBAQZ,oBACd,MAAM,6BACL"}
1
+ {"version":3,"file":"createOAuthProvider.d.ts","names":[],"sources":["../../src/auth/createOAuthProvider.ts"],"mappings":";;;;iBAiCgB,wBAAwB;KAgB5B;EACV;;EAEA,QAAQ,QAAQ;IAAiB;;EACjC,SAAS;EACT;;EAEA,qBAAqB,KAAK;;;;;;;cAmFf,8BACX,SAAS,YACT,qBACC;;;;;;iBAwBa,oBACd,MAAM,6BACL"}
@@ -26,6 +26,64 @@ function decodeServerIdFromState(state) {
26
26
  return null;
27
27
  }
28
28
  }
29
+ const anchorByStorage = /* @__PURE__ */ new WeakMap();
30
+ const anchorByScope = /* @__PURE__ */ new Map();
31
+ const anchorRegistry = new FinalizationRegistry((scopeId) => {
32
+ if (!anchorByScope.get(scopeId)?.deref()) anchorByScope.delete(scopeId);
33
+ });
34
+ const getStorageIdentity = (storage) => {
35
+ const existing = anchorByStorage.get(storage);
36
+ if (existing) return existing;
37
+ const { scopeId } = storage;
38
+ if (scopeId === void 0) return storage;
39
+ let anchor = anchorByScope.get(scopeId)?.deref();
40
+ if (!anchor) {
41
+ anchor = {};
42
+ anchorByScope.set(scopeId, new WeakRef(anchor));
43
+ anchorRegistry.register(anchor, scopeId);
44
+ }
45
+ anchorByStorage.set(storage, anchor);
46
+ return anchor;
47
+ };
48
+ const persistenceByIdentity = /* @__PURE__ */ new WeakMap();
49
+ const getPersistence = (storage, serverId) => {
50
+ const identity = getStorageIdentity(storage);
51
+ let byServerId = persistenceByIdentity.get(identity);
52
+ if (!byServerId) {
53
+ byServerId = /* @__PURE__ */ new Map();
54
+ persistenceByIdentity.set(identity, byServerId);
55
+ }
56
+ let persistence = byServerId.get(serverId);
57
+ if (!persistence) {
58
+ persistence = {
59
+ cached: null,
60
+ cachePromise: null,
61
+ queue: Promise.resolve(),
62
+ invalidated: false
63
+ };
64
+ byServerId.set(serverId, persistence);
65
+ }
66
+ return persistence;
67
+ };
68
+ /**
69
+ * Clears persisted OAuth state after the in-flight load and every queued write
70
+ * for that server have settled, so a discarded provider cannot recreate the
71
+ * record it was mid-save on.
72
+ */
73
+ const clearOAuthProviderAuthState = async (storage, serverId) => {
74
+ const identity = getStorageIdentity(storage);
75
+ const byServerId = persistenceByIdentity.get(identity);
76
+ const persistence = byServerId?.get(serverId);
77
+ if (!byServerId || !persistence) {
78
+ await storage.clearAuthState(serverId);
79
+ return;
80
+ }
81
+ persistence.invalidated = true;
82
+ byServerId.delete(serverId);
83
+ if (byServerId.size === 0) persistenceByIdentity.delete(identity);
84
+ await Promise.allSettled([persistence.cachePromise, persistence.queue]);
85
+ await storage.clearAuthState(serverId);
86
+ };
29
87
  /**
30
88
  * Builds an OAuthClientProvider for the MCP SDK, backed by MCPStorage.
31
89
  * Token refresh and DCR are handled by the SDK; this provider only mediates
@@ -33,34 +91,50 @@ function decodeServerIdFromState(state) {
33
91
  */
34
92
  function createOAuthProvider(opts) {
35
93
  const { serverId, config, storage, redirectUri, onAuthorizationUrl } = opts;
36
- let cached = null;
37
- const loadCache = async () => {
38
- if (cached) return cached;
39
- const persisted = await storage.loadAuthState(serverId);
40
- const initial = {};
41
- if (persisted?.tokens) initial.tokens = persisted.tokens;
42
- if (config.clientId) {
43
- const ci = {
44
- client_id: config.clientId,
45
- redirect_uris: [redirectUri]
46
- };
47
- if (config.clientSecret) ci.client_secret = config.clientSecret;
48
- initial.clientInformation = ci;
49
- } else if (persisted?.clientInformation) initial.clientInformation = persisted.clientInformation;
50
- if (persisted?.codeVerifier) initial.codeVerifier = persisted.codeVerifier;
51
- if (persisted?.discoveryState) initial.discoveryState = persisted.discoveryState;
52
- cached = initial;
53
- return cached;
94
+ const persistence = getPersistence(storage, serverId);
95
+ let pendingState;
96
+ const staticClientInformation = (() => {
97
+ if (!config.clientId) return void 0;
98
+ const ci = {
99
+ client_id: config.clientId,
100
+ redirect_uris: [redirectUri]
101
+ };
102
+ if (config.clientSecret) ci.client_secret = config.clientSecret;
103
+ return ci;
104
+ })();
105
+ const loadCache = () => {
106
+ if (persistence.cached) return Promise.resolve(persistence.cached);
107
+ if (persistence.cachePromise) return persistence.cachePromise;
108
+ persistence.cachePromise = storage.loadAuthState(serverId).then((persisted) => {
109
+ const initial = {};
110
+ if (persisted?.tokens) initial.tokens = persisted.tokens;
111
+ if (persisted?.clientInformation) initial.clientInformation = persisted.clientInformation;
112
+ if (persisted?.codeVerifier) initial.codeVerifier = persisted.codeVerifier;
113
+ if (persisted?.state) initial.state = persisted.state;
114
+ if (persisted?.discoveryState) initial.discoveryState = persisted.discoveryState;
115
+ persistence.cached = initial;
116
+ return initial;
117
+ }, (error) => {
118
+ persistence.cachePromise = null;
119
+ throw error;
120
+ });
121
+ return persistence.cachePromise;
54
122
  };
55
- const persist = async () => {
56
- const c = cached;
57
- if (!c) return;
58
- const next = {};
59
- if (c.tokens) next.tokens = c.tokens;
60
- if (c.clientInformation) next.clientInformation = c.clientInformation;
61
- if (c.codeVerifier) next.codeVerifier = c.codeVerifier;
62
- if (c.discoveryState) next.discoveryState = c.discoveryState;
63
- await storage.saveAuthState(serverId, next);
123
+ const persist = () => {
124
+ const task = persistence.queue.then(async () => {
125
+ if (persistence.invalidated) return;
126
+ const c = persistence.cached;
127
+ if (!c) return;
128
+ const next = {};
129
+ if (c.tokens) next.tokens = c.tokens;
130
+ if (c.clientInformation) next.clientInformation = c.clientInformation;
131
+ if (c.codeVerifier) next.codeVerifier = c.codeVerifier;
132
+ if (c.state) next.state = c.state;
133
+ if (c.discoveryState) next.discoveryState = c.discoveryState;
134
+ await storage.saveAuthState(serverId, next);
135
+ });
136
+ persistence.queue = task.catch(() => {});
137
+ return task;
64
138
  };
65
139
  const clientMetadata = {
66
140
  client_name: "assistant-ui",
@@ -79,10 +153,12 @@ function createOAuthProvider(opts) {
79
153
  },
80
154
  state() {
81
155
  const nonce = typeof crypto !== "undefined" && "randomUUID" in crypto ? crypto.randomUUID() : `${Date.now()}.${Math.random()}`;
82
- return `${encodeServerIdInState(serverId)}.${nonce}`;
156
+ pendingState = `${encodeServerIdInState(serverId)}.${nonce}`;
157
+ return pendingState;
83
158
  },
84
159
  async clientInformation() {
85
- return (await loadCache()).clientInformation;
160
+ const c = await loadCache();
161
+ return staticClientInformation ?? c.clientInformation;
86
162
  },
87
163
  async saveClientInformation(info) {
88
164
  const c = await loadCache();
@@ -95,6 +171,7 @@ function createOAuthProvider(opts) {
95
171
  async saveTokens(tokens) {
96
172
  const c = await loadCache();
97
173
  c.tokens = tokens;
174
+ delete c.state;
98
175
  await persist();
99
176
  },
100
177
  async redirectToAuthorization(url) {
@@ -103,6 +180,10 @@ function createOAuthProvider(opts) {
103
180
  async saveCodeVerifier(codeVerifier) {
104
181
  const c = await loadCache();
105
182
  c.codeVerifier = codeVerifier;
183
+ if (pendingState) {
184
+ c.state = pendingState;
185
+ pendingState = void 0;
186
+ }
106
187
  await persist();
107
188
  },
108
189
  async codeVerifier() {
@@ -122,13 +203,16 @@ function createOAuthProvider(opts) {
122
203
  const c = await loadCache();
123
204
  if (scope === "all" || scope === "tokens") delete c.tokens;
124
205
  if (scope === "all" || scope === "client") delete c.clientInformation;
125
- if (scope === "all" || scope === "verifier") delete c.codeVerifier;
206
+ if (scope === "all" || scope === "verifier") {
207
+ delete c.codeVerifier;
208
+ delete c.state;
209
+ }
126
210
  if (scope === "all" || scope === "discovery") delete c.discoveryState;
127
211
  await persist();
128
212
  }
129
213
  };
130
214
  }
131
215
  //#endregion
132
- export { createOAuthProvider, decodeServerIdFromState };
216
+ export { clearOAuthProviderAuthState, createOAuthProvider, decodeServerIdFromState };
133
217
 
134
218
  //# sourceMappingURL=createOAuthProvider.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"createOAuthProvider.js","names":["OAuthClientProvider","OAuthClientInformationFull","OAuthClientMetadata","OAuthDiscoveryState","OAuthTokens","MCPStorage","MCPAuthConfig","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","config","Extract","type","storage","redirectUri","onAuthorizationUrl","url","URL","createOAuthProvider","opts","Cache","tokens","clientInformation","codeVerifier","discoveryState","cached","loadCache","Promise","persisted","loadAuthState","initial","clientId","ci","client_id","redirect_uris","clientSecret","client_secret","persist","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\";\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 /** 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\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 { serverId, config, storage, redirectUri, onAuthorizationUrl } = opts;\n\n type Cache = {\n tokens?: OAuthTokens | undefined;\n clientInformation?: OAuthClientInformationFull | undefined;\n codeVerifier?: string | undefined;\n discoveryState?: OAuthDiscoveryState | undefined;\n };\n let cached: Cache | null = null;\n\n const loadCache = async (): Promise<Cache> => {\n if (cached) return cached;\n const persisted = await storage.loadAuthState(serverId);\n const initial: Cache = {};\n if (persisted?.tokens) initial.tokens = persisted.tokens;\n if (config.clientId) {\n const ci: OAuthClientInformationFull = {\n client_id: config.clientId,\n redirect_uris: [redirectUri],\n };\n if (config.clientSecret) ci.client_secret = config.clientSecret;\n initial.clientInformation = ci;\n } else if (persisted?.clientInformation) {\n initial.clientInformation = persisted.clientInformation;\n }\n if (persisted?.codeVerifier) initial.codeVerifier = persisted.codeVerifier;\n if (persisted?.discoveryState)\n initial.discoveryState = persisted.discoveryState;\n cached = initial;\n return cached;\n };\n\n const persist = async () => {\n const c = cached;\n if (!c) return;\n const next: Parameters<typeof storage.saveAuthState>[1] = {};\n if (c.tokens) next.tokens = c.tokens;\n if (c.clientInformation) next.clientInformation = c.clientInformation;\n if (c.codeVerifier) next.codeVerifier = c.codeVerifier;\n if (c.discoveryState) next.discoveryState = c.discoveryState;\n await storage.saveAuthState(serverId, next);\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 return `${encodeServerIdInState(serverId)}.${nonce}`;\n },\n async clientInformation() {\n const c = await loadCache();\n return c.clientInformation;\n },\n async saveClientInformation(info) {\n const c = await loadCache();\n c.clientInformation = info as OAuthClientInformationFull;\n await persist();\n },\n async tokens() {\n const c = await loadCache();\n return c.tokens;\n },\n async saveTokens(tokens) {\n const c = await loadCache();\n c.tokens = tokens;\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 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\") delete c.tokens;\n if (scope === \"all\" || scope === \"client\") delete c.clientInformation;\n if (scope === \"all\" || scope === \"verifier\") delete c.codeVerifier;\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","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","config","Extract","type","storage","redirectUri","onAuthorizationUrl","url","URL","OAuthProviderCache","tokens","clientInformation","codeVerifier","discoveryState","OAuthProviderPersistence","cached","cachePromise","Promise","queue","invalidated","anchorByStorage","WeakMap","anchorByScope","Map","WeakRef","anchorRegistry","FinalizationRegistry","scopeId","get","deref","delete","getStorageIdentity","existing","undefined","anchor","set","register","persistenceByIdentity","getPersistence","identity","byServerId","persistence","resolve","clearOAuthProviderAuthState","clearAuthState","size","allSettled","createOAuthProvider","opts","pendingState","staticClientInformation","clientId","ci","client_id","redirect_uris","clientSecret","client_secret","loadCache","loadAuthState","then","persisted","initial","error","persist","task","c","next","Parameters","saveAuthState","catch","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\";\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 /** 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 tokens?: OAuthTokens | undefined;\n clientInformation?: OAuthClientInformationFull | undefined;\n codeVerifier?: string | undefined;\n state?: string | undefined;\n discoveryState?: OAuthDiscoveryState | undefined;\n};\n\ntype OAuthProviderPersistence = {\n cached: OAuthProviderCache | null;\n cachePromise: Promise<OAuthProviderCache> | 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): OAuthProviderPersistence => {\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 cached: null,\n cachePromise: null,\n queue: Promise.resolve(),\n invalidated: false,\n };\n byServerId.set(serverId, persistence);\n }\n return persistence;\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 await Promise.allSettled([persistence.cachePromise, 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 { serverId, config, storage, redirectUri, onAuthorizationUrl } = opts;\n const persistence = getPersistence(storage, serverId);\n let pendingState: string | undefined;\n\n // The cache is shared with every other provider for this (storage, serverId),\n // so a statically configured client stays a read-time overlay owned by this\n // provider. Writing it into the cache would leak this provider's registration\n // to a replacement built for a different, or absent, clientId.\n const staticClientInformation = (():\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\n const loadCache = (): Promise<OAuthProviderCache> => {\n if (persistence.cached) return Promise.resolve(persistence.cached);\n if (persistence.cachePromise) return persistence.cachePromise;\n\n persistence.cachePromise = storage.loadAuthState(serverId).then(\n (persisted) => {\n const initial: OAuthProviderCache = {};\n if (persisted?.tokens) initial.tokens = persisted.tokens;\n if (persisted?.clientInformation)\n initial.clientInformation = persisted.clientInformation;\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 persistence.cached = initial;\n return initial;\n },\n (error) => {\n persistence.cachePromise = null;\n throw error;\n },\n );\n return persistence.cachePromise;\n };\n\n const persist = () => {\n const task = persistence.queue.then(async () => {\n if (persistence.invalidated) return;\n const c = persistence.cached;\n if (!c) return;\n const next: Parameters<typeof storage.saveAuthState>[1] = {};\n if (c.tokens) next.tokens = c.tokens;\n if (c.clientInformation) next.clientInformation = c.clientInformation;\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 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 return staticClientInformation ?? c.clientInformation;\n },\n async saveClientInformation(info) {\n const c = await loadCache();\n c.clientInformation = info as OAuthClientInformationFull;\n await persist();\n },\n async tokens() {\n const c = await loadCache();\n return c.tokens;\n },\n async saveTokens(tokens) {\n const c = await loadCache();\n c.tokens = tokens;\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\") delete c.tokens;\n if (scope === \"all\" || scope === \"client\") delete c.clientInformation;\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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"}
@@ -4,6 +4,7 @@ type MCPPersistedAuthState = {
4
4
  tokens?: OAuthTokens;
5
5
  clientInformation?: OAuthClientInformationFull;
6
6
  codeVerifier?: string;
7
+ state?: string;
7
8
  discoveryState?: OAuthDiscoveryState;
8
9
  /** Bearer token (entered at add-form time). */
9
10
  token?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","names":[],"sources":["../../src/auth/types.ts"],"mappings":";;KAMY;EACV,SAAS;EACT,oBAAoB;EACpB;EACA,iBAAiB;;EAEjB"}
1
+ {"version":3,"file":"types.d.ts","names":[],"sources":["../../src/auth/types.ts"],"mappings":";;KAMY;EACV,SAAS;EACT,oBAAoB;EACpB;EACA;EACA,iBAAiB;;EAEjB"}
@@ -1 +1 @@
1
- {"version":3,"file":"useMcpOAuthCallback.d.ts","names":[],"sources":["../../src/hooks/useMcpOAuthCallback.tsx"],"mappings":";;cAKa,8BACX,cACA,4BACC;KAWS;;EAEV;EACA,cAAc;EACd,WAAW,KAAK;;KAGN;EACV;EACA;EACA,OAAO;;iBAGO,oBACd,OAAM,6BACL;cAsDU,kBAAkB,GAC7B;EACE,YAAY,QAAQ,8BAA8B"}
1
+ {"version":3,"file":"useMcpOAuthCallback.d.ts","names":[],"sources":["../../src/hooks/useMcpOAuthCallback.tsx"],"mappings":";;cAYa,8BACX,cACA,4BACC;KAWS;;EAEV;EACA,cAAc;EACd,WAAW,KAAK;;KAGN;EACV;EACA;EACA,OAAO;;iBAGO,oBACd,OAAM,6BACL;cAkDU,kBAAkB,GAC7B;EACE,YAAY,QAAQ,8BAA8B"}
@@ -2,7 +2,7 @@ import { decodeServerIdFromState } from "../auth/createOAuthProvider.js";
2
2
  import { invokeMcpCallback } from "../utils/invokeMcpCallback.js";
3
3
  import { useAui } from "@assistant-ui/store";
4
4
  import { c } from "@assistant-ui/tap/react-shim/compiler-runtime";
5
- import { useEffect, useRef, useState } from "@assistant-ui/tap/react-shim";
5
+ import { useEffect, useInsertionEffect, useRef, useState } from "@assistant-ui/tap/react-shim";
6
6
  import { Fragment, jsx } from "react/jsx-runtime";
7
7
  //#region src/hooks/useMcpOAuthCallback.tsx
8
8
  const createMcpOAuthCallbackError = (err, serverId) => {
@@ -19,7 +19,9 @@ function useMcpOAuthCallback(opts = {}) {
19
19
  });
20
20
  const startedRef = useRef(null);
21
21
  const optsRef = useRef(opts);
22
- optsRef.current = opts;
22
+ useInsertionEffect(() => {
23
+ optsRef.current = opts;
24
+ });
23
25
  useEffect(() => {
24
26
  const url = opts.url ?? (typeof window !== "undefined" ? window.location.href : null);
25
27
  if (!url) return;
@@ -28,11 +30,8 @@ function useMcpOAuthCallback(opts = {}) {
28
30
  (async () => {
29
31
  let serverId = null;
30
32
  try {
31
- const parsed = new URL(url);
32
- const state = parsed.searchParams.get("state");
33
+ const state = new URL(url).searchParams.get("state");
33
34
  if (state) serverId = decodeServerIdFromState(state);
34
- const error_0 = parsed.searchParams.get("error");
35
- if (error_0) throw new Error(parsed.searchParams.get("error_description") ?? error_0);
36
35
  if (!state) throw new Error("missing \"state\" parameter");
37
36
  if (!serverId) throw new Error("state was not created by assistant-ui MCP");
38
37
  setResult({
@@ -1 +1 @@
1
- {"version":3,"file":"useMcpOAuthCallback.js","names":["FC","ReactNode","useEffect","useRef","useState","useAui","decodeServerIdFromState","invokeMcpCallback","createMcpOAuthCallbackError","err","serverId","Error","message","String","cause","UseMcpOAuthCallbackOptions","url","onComplete","onError","UseMcpOAuthCallbackResult","status","error","useMcpOAuthCallback","opts","aui","result","setResult","startedRef","optsRef","current","window","location","href","parsed","URL","state","searchParams","get","mcp","server","id","completeAuth","McpOAuthCallback","children","t0","$","_c","t1","t2"],"sources":["../../src/hooks/useMcpOAuthCallback.tsx"],"sourcesContent":["import { type FC, type ReactNode, useEffect, useRef, useState } from \"react\";\nimport { useAui } from \"@assistant-ui/store\";\nimport { decodeServerIdFromState } from \"../auth/createOAuthProvider\";\nimport { invokeMcpCallback } from \"../utils/invokeMcpCallback\";\n\nexport const createMcpOAuthCallbackError = (\n err: unknown,\n serverId: string | null,\n): Error => {\n const message = err instanceof Error ? err.message : String(err);\n if (serverId) {\n return new Error(\n `MCP OAuth callback for server \"${serverId}\" failed: ${message}`,\n { cause: err },\n );\n }\n return new Error(`MCP OAuth callback failed: ${message}`, { cause: err });\n};\n\nexport type UseMcpOAuthCallbackOptions = {\n /** Defaults to `window.location.href`. */\n url?: string;\n onComplete?: (serverId: string) => void;\n onError?: (err: Error) => void;\n};\n\nexport type UseMcpOAuthCallbackResult = {\n status: \"idle\" | \"running\" | \"done\" | \"error\";\n serverId: string | null;\n error: Error | null;\n};\n\nexport function useMcpOAuthCallback(\n opts: UseMcpOAuthCallbackOptions = {},\n): UseMcpOAuthCallbackResult {\n const aui = useAui();\n const [result, setResult] = useState<UseMcpOAuthCallbackResult>({\n status: \"idle\",\n serverId: null,\n error: null,\n });\n // Guard against React 18 Strict Mode's mount-unmount-remount: the effect\n // body must not run completeAuth twice for the same URL, otherwise the\n // single-use OAuth code is double-redeemed and the second attempt 4xxs.\n const startedRef = useRef<string | null>(null);\n const optsRef = useRef(opts);\n optsRef.current = opts;\n\n useEffect(() => {\n const url =\n opts.url ?? (typeof window !== \"undefined\" ? window.location.href : null);\n if (!url) return;\n if (startedRef.current === url) return;\n startedRef.current = url;\n\n void (async () => {\n let serverId: string | null = null;\n try {\n const parsed = new URL(url);\n const state = parsed.searchParams.get(\"state\");\n if (state) serverId = decodeServerIdFromState(state);\n const error = parsed.searchParams.get(\"error\");\n if (error) {\n throw new Error(\n parsed.searchParams.get(\"error_description\") ?? error,\n );\n }\n if (!state) throw new Error('missing \"state\" parameter');\n if (!serverId) {\n throw new Error(\"state was not created by assistant-ui MCP\");\n }\n setResult({ status: \"running\", serverId, error: null });\n await aui.mcp.server({ id: serverId }).completeAuth(url);\n setResult({ status: \"done\", serverId, error: null });\n } catch (err) {\n const error = createMcpOAuthCallbackError(err, serverId);\n setResult({ status: \"error\", serverId, error });\n invokeMcpCallback(\"onError\", optsRef.current.onError, error);\n return;\n }\n\n invokeMcpCallback(\"onComplete\", optsRef.current.onComplete, serverId);\n })();\n }, [aui, opts.url]);\n\n return result;\n}\n\nexport const McpOAuthCallback: FC<\n UseMcpOAuthCallbackOptions & {\n children?: (result: UseMcpOAuthCallbackResult) => ReactNode;\n }\n> = ({ children, ...opts }) => {\n const result = useMcpOAuthCallback(opts);\n if (children) return <>{children(result)}</>;\n return null;\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"useMcpOAuthCallback.js","names":["FC","ReactNode","useEffect","useInsertionEffect","useRef","useState","useAui","decodeServerIdFromState","invokeMcpCallback","createMcpOAuthCallbackError","err","serverId","Error","message","String","cause","UseMcpOAuthCallbackOptions","url","onComplete","onError","UseMcpOAuthCallbackResult","status","error","useMcpOAuthCallback","opts","aui","result","setResult","startedRef","optsRef","current","window","location","href","parsed","URL","state","searchParams","get","mcp","server","id","completeAuth","McpOAuthCallback","children","t0","$","_c","t1","t2"],"sources":["../../src/hooks/useMcpOAuthCallback.tsx"],"sourcesContent":["import {\n type FC,\n type ReactNode,\n useEffect,\n useInsertionEffect,\n useRef,\n useState,\n} from \"react\";\nimport { useAui } from \"@assistant-ui/store\";\nimport { decodeServerIdFromState } from \"../auth/createOAuthProvider\";\nimport { invokeMcpCallback } from \"../utils/invokeMcpCallback\";\n\nexport const createMcpOAuthCallbackError = (\n err: unknown,\n serverId: string | null,\n): Error => {\n const message = err instanceof Error ? err.message : String(err);\n if (serverId) {\n return new Error(\n `MCP OAuth callback for server \"${serverId}\" failed: ${message}`,\n { cause: err },\n );\n }\n return new Error(`MCP OAuth callback failed: ${message}`, { cause: err });\n};\n\nexport type UseMcpOAuthCallbackOptions = {\n /** Defaults to `window.location.href`. */\n url?: string;\n onComplete?: (serverId: string) => void;\n onError?: (err: Error) => void;\n};\n\nexport type UseMcpOAuthCallbackResult = {\n status: \"idle\" | \"running\" | \"done\" | \"error\";\n serverId: string | null;\n error: Error | null;\n};\n\nexport function useMcpOAuthCallback(\n opts: UseMcpOAuthCallbackOptions = {},\n): UseMcpOAuthCallbackResult {\n const aui = useAui();\n const [result, setResult] = useState<UseMcpOAuthCallbackResult>({\n status: \"idle\",\n serverId: null,\n error: null,\n });\n // Guard against React 18 Strict Mode's mount-unmount-remount: the effect\n // body must not run completeAuth twice for the same URL, otherwise the\n // single-use OAuth code is double-redeemed and the second attempt 4xxs.\n const startedRef = useRef<string | null>(null);\n const optsRef = useRef(opts);\n useInsertionEffect(() => {\n optsRef.current = opts;\n });\n\n useEffect(() => {\n const url =\n opts.url ?? (typeof window !== \"undefined\" ? window.location.href : null);\n if (!url) return;\n if (startedRef.current === url) return;\n startedRef.current = url;\n\n void (async () => {\n let serverId: string | null = null;\n try {\n const parsed = new URL(url);\n const state = parsed.searchParams.get(\"state\");\n if (state) serverId = decodeServerIdFromState(state);\n if (!state) throw new Error('missing \"state\" parameter');\n if (!serverId) {\n throw new Error(\"state was not created by assistant-ui MCP\");\n }\n setResult({ status: \"running\", serverId, error: null });\n await aui.mcp.server({ id: serverId }).completeAuth(url);\n setResult({ status: \"done\", serverId, error: null });\n } catch (err) {\n const error = createMcpOAuthCallbackError(err, serverId);\n setResult({ status: \"error\", serverId, error });\n invokeMcpCallback(\"onError\", optsRef.current.onError, error);\n return;\n }\n\n invokeMcpCallback(\"onComplete\", optsRef.current.onComplete, serverId);\n })();\n }, [aui, opts.url]);\n\n return result;\n}\n\nexport const McpOAuthCallback: FC<\n UseMcpOAuthCallbackOptions & {\n children?: (result: UseMcpOAuthCallbackResult) => ReactNode;\n }\n> = ({ children, ...opts }) => {\n const result = useMcpOAuthCallback(opts);\n if (children) return <>{children(result)}</>;\n return null;\n};\n"],"mappings":";;;;;;;AAYA,MAAaS,+BACXC,KACAC,aACU;CACV,MAAME,UAAUH,eAAeE,QAAQF,IAAIG,UAAUC,OAAOJ,GAAG;CAC/D,IAAIC,UACF,OAAO,IAAIC,MACT,kCAAkCD,SAAQ,YAAaE,WACvD,EAAEE,OAAOL,IAAI,CACf;CAEF,OAAO,IAAIE,MAAM,8BAA8BC,WAAW,EAAEE,OAAOL,IAAI,CAAC;AAC1E;AAeA,SAAgBa,oBACdC,OAAmC,CAAC,GACT;CAC3B,MAAMC,MAAMnB,OAAO;CACnB,MAAM,CAACoB,QAAQC,aAAatB,SAAoC;EAC9DgB,QAAQ;EACRV,UAAU;EACVW,OAAO;CACT,CAAC;CAID,MAAMM,aAAaxB,OAAsB,IAAI;CAC7C,MAAMyB,UAAUzB,OAAOoB,IAAI;CAC3BrB,yBAAyB;EACvB0B,QAAQC,UAAUN;CACpB,CAAC;CAEDtB,gBAAgB;EACd,MAAMe,MACJO,KAAKP,QAAQ,OAAOc,WAAW,cAAcA,OAAOC,SAASC,OAAO;EACtE,IAAI,CAAChB,KAAK;EACV,IAAIW,WAAWE,YAAYb,KAAK;EAChCW,WAAWE,UAAUb;EAErB,CAAM,YAAY;GAChB,IAAIN,WAA0B;GAC9B,IAAI;IAEF,MAAMyB,QAAQF,IADKC,IAAIlB,GACTiB,CAAM,CAACG,aAAaC,IAAI,OAAO;IAC7C,IAAIF,OAAOzB,WAAWJ,wBAAwB6B,KAAK;IACnD,IAAI,CAACA,OAAO,MAAM,IAAIxB,MAAM,6BAA2B;IACvD,IAAI,CAACD,UACH,MAAM,IAAIC,MAAM,2CAA2C;IAE7De,UAAU;KAAEN,QAAQ;KAAWV;KAAUW,OAAO;IAAK,CAAC;IACtD,MAAMG,IAAIc,IAAIC,OAAO,EAAEC,IAAI9B,SAAS,CAAC,CAAC,CAAC+B,aAAazB,GAAG;IACvDU,UAAU;KAAEN,QAAQ;KAAQV;KAAUW,OAAO;IAAK,CAAC;GACrD,SAASZ,KAAK;IACZ,MAAMY,QAAQb,4BAA4BC,KAAKC,QAAQ;IACvDgB,UAAU;KAAEN,QAAQ;KAASV;KAAUW;IAAM,CAAC;IAC9Cd,kBAAkB,WAAWqB,QAAQC,QAAQX,SAASG,KAAK;IAC3D;GACF;GAEAd,kBAAkB,cAAcqB,QAAQC,QAAQZ,YAAYP,QAAQ;EACtE,EAAA,CAAG;CACL,GAAG,CAACc,KAAKD,KAAKP,GAAG,CAAC;CAElB,OAAOS;AACT;AAEA,MAAaiB,oBAITE,OAAA;CAAA,MAAAC,IAAAC,EAAA,CAAA;CAAA,IAAAH;CAAA,IAAApB;CAAA,IAAAsB,EAAA,OAAAD,IAAA;EAAC,CAAA,CAAAD,UAAA,GAAApB,QAAAqB;EAAqBC,EAAA,KAAAD;EAAAC,EAAA,KAAAF;EAAAE,EAAA,KAAAtB;CAAA,OAAA;EAAAoB,WAAAE,EAAA;EAAAtB,OAAAsB,EAAA;CAAA;CACxB,MAAApB,SAAeH,oBAAoBC,IAAI;CACvC,IAAIoB,UAAQ;EAAA,IAAAI;EAAA,IAAAF,EAAA,OAAAF,YAAAE,EAAA,OAAApB,QAAA;GAAYsB,KAAAJ,SAASlB,MAAM;GAACoB,EAAA,KAAAF;GAAAE,EAAA,KAAApB;GAAAoB,EAAA,KAAAE;EAAA,OAAAA,KAAAF,EAAA;EAAA,IAAAG;EAAA,IAAAH,EAAA,OAAAE,IAAA;GAAnBC,KAAA,oBAAA,UAAA,EAAA,UAAGD,GAAgB,CAAA;GAAIF,EAAA,KAAAE;GAAAF,EAAA,KAAAG;EAAA,OAAAA,KAAAH,EAAA;EAAA,OAAvBG;CAAuB;CAAC,OACtC;AAAI"}
@@ -1 +1 @@
1
- {"version":3,"file":"McpServerIcon.js","names":["ComponentPropsWithoutRef","ComponentRef","forwardRef","Primitive","useAuiState","McpServerPrimitiveIcon","Element","img","Props","Omit","src","alt","t0","ref","$","_c","props","iconUrl","_temp","name","_temp2","effective","t1","t2","displayName","s","mcpServer","icon","s_0"],"sources":["../../../src/primitives/server/McpServerIcon.tsx"],"sourcesContent":["import {\n type ComponentPropsWithoutRef,\n type ComponentRef,\n forwardRef,\n} from \"react\";\nimport { Primitive } from \"@radix-ui/react-primitive\";\nimport { useAuiState } from \"@assistant-ui/store\";\n\nexport namespace McpServerPrimitiveIcon {\n export type Element = ComponentRef<typeof Primitive.img>;\n export type Props = Omit<\n ComponentPropsWithoutRef<typeof Primitive.img>,\n \"src\" | \"alt\"\n > & {\n /** Override the icon URL. Defaults to the server's icon prop. */\n src?: string;\n alt?: string;\n };\n}\n\nexport const McpServerPrimitiveIcon = forwardRef<\n McpServerPrimitiveIcon.Element,\n McpServerPrimitiveIcon.Props\n>(({ src, alt, ...props }, ref) => {\n const iconUrl = useAuiState((s) => s.mcpServer.icon ?? null);\n const name = useAuiState((s) => s.mcpServer.name);\n const effective = src ?? iconUrl;\n if (!effective) return null;\n return (\n <Primitive.img {...props} ref={ref} src={effective} alt={alt ?? name} />\n );\n});\n\nMcpServerPrimitiveIcon.displayName = \"McpServerPrimitive.Icon\";\n"],"mappings":";;;;;;AAoBA,MAAaK,yBAAyBH,YAGpCU,IAAAC,QAAA;CAAA,MAAAC,IAAAC,EAAA,CAAA;CAAA,IAAAJ;CAAA,IAAAK;CAAA,IAAAN;CAAA,IAAAI,EAAA,OAAAF,IAAA;EAAC,CAAA,CAAAF,KAAAC,QAAAK,SAAAJ;EAAsBE,EAAA,KAAAF;EAAAE,EAAA,KAAAH;EAAAG,EAAA,KAAAE;EAAAF,EAAA,KAAAJ;CAAA,OAAA;EAAAC,MAAAG,EAAA;EAAAE,QAAAF,EAAA;EAAAJ,MAAAI,EAAA;CAAA;CACvB,MAAAG,UAAgBb,YAAYc,KAA+B;CAC3D,MAAAC,OAAaf,YAAYgB,MAAuB;CAChD,MAAAC,YAAkBX,OAAAO;CAClB,IAAI,CAACI,WAAS,OAAS;CAEoC,MAAAC,KAAAX,OAAAQ;CAAW,IAAAI;CAAA,IAAAT,EAAA,OAAAO,aAAAP,EAAA,OAAAE,SAAAF,EAAA,OAAAD,OAAAC,EAAA,OAAAQ,IAAA;EAApEC,KAAA,oBAAA,UAAA,KAAA;GAAA,GAAmBP;GAAYH;GAAUQ,KAAAA;GAAgB,KAAAC;EAAW,CAAA;EAAIR,EAAA,KAAAO;EAAAP,EAAA,KAAAE;EAAAF,EAAA,KAAAD;EAAAC,EAAA,KAAAQ;EAAAR,EAAA,KAAAS;CAAA,OAAAA,KAAAT,EAAA;CAAA,OAAxES;AAAwE,CAE3E;AAEDlB,uBAAuBmB,cAAc;AAVnC,SAAAN,MAAAO,GAAA;CAAA,OACmCA,EAACC,UAAUC,QAAX;AAAwB;AAD3D,SAAAP,OAAAQ,KAAA;CAAA,OAEgCH,IAACC,UAAUP;AAAK"}
1
+ {"version":3,"file":"McpServerIcon.js","names":["ComponentPropsWithoutRef","ComponentRef","forwardRef","Primitive","useAuiState","McpServerPrimitiveIcon","Element","img","Props","Omit","src","alt","t0","ref","$","_c","props","iconUrl","_temp","name","_temp2","effective","t1","t2","displayName","s","mcpServer","icon","s_0"],"sources":["../../../src/primitives/server/McpServerIcon.tsx"],"sourcesContent":["import {\n type ComponentPropsWithoutRef,\n type ComponentRef,\n forwardRef,\n} from \"react\";\nimport { Primitive } from \"@radix-ui/react-primitive\";\nimport { useAuiState } from \"@assistant-ui/store\";\n\nexport namespace McpServerPrimitiveIcon {\n export type Element = ComponentRef<typeof Primitive.img>;\n export type Props = Omit<\n ComponentPropsWithoutRef<typeof Primitive.img>,\n \"src\" | \"alt\"\n > & {\n /** Override the icon URL. Defaults to the server's icon prop. */\n src?: string;\n alt?: string;\n };\n}\n\nexport const McpServerPrimitiveIcon = forwardRef<\n McpServerPrimitiveIcon.Element,\n McpServerPrimitiveIcon.Props\n>(({ src, alt, ...props }, ref) => {\n const iconUrl = useAuiState((s) => s.mcpServer.icon ?? null);\n const name = useAuiState((s) => s.mcpServer.name);\n const effective = src ?? iconUrl;\n if (!effective) return null;\n return (\n <Primitive.img {...props} ref={ref} src={effective} alt={alt ?? name} />\n );\n});\n\nMcpServerPrimitiveIcon.displayName = \"McpServerPrimitive.Icon\";\n"],"mappings":";;;;;;AAoBA,MAAaK,yBAAyBH,YAGpCU,IAAAC,QAAA;CAAA,MAAAC,IAAAC,EAAA,CAAA;CAAA,IAAAJ;CAAA,IAAAK;CAAA,IAAAN;CAAA,IAAAI,EAAA,OAAAF,IAAA;EAAC,CAAA,CAAAF,KAAAC,KAAA,GAAAK,SAAAJ;EAAsBE,EAAA,KAAAF;EAAAE,EAAA,KAAAH;EAAAG,EAAA,KAAAE;EAAAF,EAAA,KAAAJ;CAAA,OAAA;EAAAC,MAAAG,EAAA;EAAAE,QAAAF,EAAA;EAAAJ,MAAAI,EAAA;CAAA;CACvB,MAAAG,UAAgBb,YAAYc,KAA+B;CAC3D,MAAAC,OAAaf,YAAYgB,MAAuB;CAChD,MAAAC,YAAkBX,OAAAO;CAClB,IAAI,CAACI,WAAS,OAAS;CAEoC,MAAAC,KAAAX,OAAAQ;CAAW,IAAAI;CAAA,IAAAT,EAAA,OAAAO,aAAAP,EAAA,OAAAE,SAAAF,EAAA,OAAAD,OAAAC,EAAA,OAAAQ,IAAA;EAApEC,KAAA,oBAAA,UAAA,KAAA;GAAA,GAAmBP;GAAYH;GAAUQ,KAAAA;GAAgB,KAAAC;EAAW,CAAA;EAAIR,EAAA,KAAAO;EAAAP,EAAA,KAAAE;EAAAF,EAAA,KAAAD;EAAAC,EAAA,KAAAQ;EAAAR,EAAA,KAAAS;CAAA,OAAAA,KAAAT,EAAA;CAAA,OAAxES;AAAwE,CAE3E;AAEDlB,uBAAuBmB,cAAc;AAVnC,SAAAN,MAAAO,GAAA;CAAA,OACmCA,EAACC,UAAUC,QAAX;AAAwB;AAD3D,SAAAP,OAAAQ,KAAA;CAAA,OAEgCH,IAACC,UAAUP;AAAK"}
@@ -1 +1 @@
1
- {"version":3,"file":"McpServerOAuthLink.js","names":["ComponentPropsWithoutRef","ComponentRef","forwardRef","Primitive","useAuiState","McpServerPrimitiveOAuthLink","Element","a","Props","Omit","href","t0","ref","$","_c","props","url","_temp","effective","t1","rel","t2","displayName","s","mcpServer","authorizationUrl"],"sources":["../../../src/primitives/server/McpServerOAuthLink.tsx"],"sourcesContent":["import {\n type ComponentPropsWithoutRef,\n type ComponentRef,\n forwardRef,\n} from \"react\";\nimport { Primitive } from \"@radix-ui/react-primitive\";\nimport { useAuiState } from \"@assistant-ui/store\";\n\nexport namespace McpServerPrimitiveOAuthLink {\n export type Element = ComponentRef<typeof Primitive.a>;\n export type Props = Omit<\n ComponentPropsWithoutRef<typeof Primitive.a>,\n \"href\"\n > & {\n /** Optional href override; defaults to the server's authorizationUrl. */\n href?: string;\n };\n}\n\nexport const McpServerPrimitiveOAuthLink = forwardRef<\n McpServerPrimitiveOAuthLink.Element,\n McpServerPrimitiveOAuthLink.Props\n>(({ href, ...props }, ref) => {\n const url = useAuiState((s) => s.mcpServer.authorizationUrl);\n const effective = href ?? url;\n if (!effective) return null;\n return (\n <Primitive.a\n target=\"_blank\"\n {...props}\n ref={ref}\n href={effective}\n rel={props.rel ?? \"noopener noreferrer\"}\n />\n );\n});\n\nMcpServerPrimitiveOAuthLink.displayName = \"McpServerPrimitive.OAuthLink\";\n"],"mappings":";;;;;;AAmBA,MAAaK,8BAA8BH,YAGzCS,IAAAC,QAAA;CAAA,MAAAC,IAAAC,EAAA,CAAA;CAAA,IAAAJ;CAAA,IAAAK;CAAA,IAAAF,EAAA,OAAAF,IAAA;EAAC,CAAA,CAAAD,SAAAK,SAAAJ;EAAkBE,EAAA,KAAAF;EAAAE,EAAA,KAAAH;EAAAG,EAAA,KAAAE;CAAA,OAAA;EAAAL,OAAAG,EAAA;EAAAE,QAAAF,EAAA;CAAA;CACnB,MAAAG,MAAYZ,YAAYa,KAAmC;CAC3D,MAAAC,YAAkBR,QAAAM;CAClB,IAAI,CAACE,WAAS,OAAS;CAOd,MAAAC,KAAAJ,MAAKK,OAAL;CAAkC,IAAAC;CAAA,IAAAR,EAAA,OAAAK,aAAAL,EAAA,OAAAE,SAAAF,EAAA,OAAAD,OAAAC,EAAA,OAAAM,IAAA;EALzCE,KAAA,oBAAA,UAAA,GAAA;GACS,QAAA;GAAQ,GACXN;GACCH;GACCM,MAAAA;GACD,KAAAC;EAAkC,CAAA;EACvCN,EAAA,KAAAK;EAAAL,EAAA,KAAAE;EAAAF,EAAA,KAAAD;EAAAC,EAAA,KAAAM;EAAAN,EAAA,KAAAQ;CAAA,OAAAA,KAAAR,EAAA;CAAA,OANFQ;AAME,CAEL;AAEDhB,4BAA4BiB,cAAc;AAfxC,SAAAL,MAAAM,GAAA;CAAA,OAC+BA,EAACC,UAAUC;AAAiB"}
1
+ {"version":3,"file":"McpServerOAuthLink.js","names":["ComponentPropsWithoutRef","ComponentRef","forwardRef","Primitive","useAuiState","McpServerPrimitiveOAuthLink","Element","a","Props","Omit","href","t0","ref","$","_c","props","url","_temp","effective","t1","rel","t2","displayName","s","mcpServer","authorizationUrl"],"sources":["../../../src/primitives/server/McpServerOAuthLink.tsx"],"sourcesContent":["import {\n type ComponentPropsWithoutRef,\n type ComponentRef,\n forwardRef,\n} from \"react\";\nimport { Primitive } from \"@radix-ui/react-primitive\";\nimport { useAuiState } from \"@assistant-ui/store\";\n\nexport namespace McpServerPrimitiveOAuthLink {\n export type Element = ComponentRef<typeof Primitive.a>;\n export type Props = Omit<\n ComponentPropsWithoutRef<typeof Primitive.a>,\n \"href\"\n > & {\n /** Optional href override; defaults to the server's authorizationUrl. */\n href?: string;\n };\n}\n\nexport const McpServerPrimitiveOAuthLink = forwardRef<\n McpServerPrimitiveOAuthLink.Element,\n McpServerPrimitiveOAuthLink.Props\n>(({ href, ...props }, ref) => {\n const url = useAuiState((s) => s.mcpServer.authorizationUrl);\n const effective = href ?? url;\n if (!effective) return null;\n return (\n <Primitive.a\n target=\"_blank\"\n {...props}\n ref={ref}\n href={effective}\n rel={props.rel ?? \"noopener noreferrer\"}\n />\n );\n});\n\nMcpServerPrimitiveOAuthLink.displayName = \"McpServerPrimitive.OAuthLink\";\n"],"mappings":";;;;;;AAmBA,MAAaK,8BAA8BH,YAGzCS,IAAAC,QAAA;CAAA,MAAAC,IAAAC,EAAA,CAAA;CAAA,IAAAJ;CAAA,IAAAK;CAAA,IAAAF,EAAA,OAAAF,IAAA;EAAC,CAAA,CAAAD,MAAA,GAAAK,SAAAJ;EAAkBE,EAAA,KAAAF;EAAAE,EAAA,KAAAH;EAAAG,EAAA,KAAAE;CAAA,OAAA;EAAAL,OAAAG,EAAA;EAAAE,QAAAF,EAAA;CAAA;CACnB,MAAAG,MAAYZ,YAAYa,KAAmC;CAC3D,MAAAC,YAAkBR,QAAAM;CAClB,IAAI,CAACE,WAAS,OAAS;CAOd,MAAAC,KAAAJ,MAAKK,OAAL;CAAkC,IAAAC;CAAA,IAAAR,EAAA,OAAAK,aAAAL,EAAA,OAAAE,SAAAF,EAAA,OAAAD,OAAAC,EAAA,OAAAM,IAAA;EALzCE,KAAA,oBAAA,UAAA,GAAA;GACS,QAAA;GAAQ,GACXN;GACCH;GACCM,MAAAA;GACD,KAAAC;EAAkC,CAAA;EACvCN,EAAA,KAAAK;EAAAL,EAAA,KAAAE;EAAAF,EAAA,KAAAD;EAAAC,EAAA,KAAAM;EAAAN,EAAA,KAAAQ;CAAA,OAAAA,KAAAR,EAAA;CAAA,OANFQ;AAME,CAEL;AAEDhB,4BAA4BiB,cAAc;AAfxC,SAAAL,MAAAM,GAAA;CAAA,OAC+BA,EAACC,UAAUC;AAAiB"}
@@ -1 +1 @@
1
- {"version":3,"file":"McpManagerResource.d.ts","names":[],"sources":["../../src/resources/McpManagerResource.ts"],"mappings":";;;;KAsBY;EACV,aAAa;EACb,UAAU;;EAEV;;EAEA;;EAEA;;cA4RW,gDAAkB,SAAA,sBAAA,OAAA"}
1
+ {"version":3,"file":"McpManagerResource.d.ts","names":[],"sources":["../../src/resources/McpManagerResource.ts"],"mappings":";;;;KAwBY;EACV,aAAa;EACb,UAAU;;EAEV;;EAEA;;EAEA;;cAyRW,gDAAkB,SAAA,sBAAA,OAAA"}
@@ -1,4 +1,6 @@
1
1
  import { assertUniqueServerIds } from "../utils/serverId.js";
2
+ import { createMcpId } from "../utils/createMcpId.js";
3
+ import { clearOAuthProviderAuthState } from "../auth/createOAuthProvider.js";
2
4
  import { McpServerResource } from "./McpServerResource.js";
3
5
  import { McpLocalStorage } from "./storage/McpLocalStorage.js";
4
6
  import { attachTransformScopes, useAssistantClientRef, useClientLookup } from "@assistant-ui/store";
@@ -318,7 +320,7 @@ const useMcpManagerResource = (props) => {
318
320
  t22 = async (t23) => {
319
321
  const { name, url, auth, connectionTimeout: connectionTimeout_0, cache, elicitation } = t23;
320
322
  const record = {
321
- id: typeof crypto !== "undefined" && "randomUUID" in crypto ? crypto.randomUUID() : `mcp-${Date.now()}-${Math.random().toString(36).slice(2)}`,
323
+ id: createMcpId(),
322
324
  name,
323
325
  url,
324
326
  auth,
@@ -339,7 +341,7 @@ const useMcpManagerResource = (props) => {
339
341
  try {
340
342
  await lookup.get({ key: id }).remove();
341
343
  } catch {
342
- await storage.clearAuthState(id);
344
+ await clearOAuthProviderAuthState(storage, id);
343
345
  setCustomServers((prev_2) => prev_2.filter((s_3) => s_3.id !== id));
344
346
  }
345
347
  };
@@ -1 +1 @@
1
- {"version":3,"file":"McpManagerResource.js","names":["useState","useEffect","useMemo","useEffectEvent","useRef","useResource","resource","withKey","useClientLookup","useAssistantClientRef","attachTransformScopes","ClientOutput","useAssistantScopeEffect","ModelContext","Tool","McpServerResource","McpLocalStorage","MCPStorage","MCPStorageElement","assertUniqueServerIds","MCPAuthConfig","MCPConnector","MCPCustomServerRecord","MCPManagerState","McpManagerResourceProps","connectors","storage","oauthRedirectUri","autoConnect","connectionTimeout","defaultRedirectUri","window","location","origin","NO_CONNECTORS","reportCustomStorageFailure","operation","error","console","persistCustomServers","records","saveCustomServers","useMcpManagerResource","props","$","_c","t0","redirectUri","t1","storageElement","t2","Symbol","for","customServers","setCustomServers","isHydrated","setIsHydrated","hydratedRef","storageRef","t3","Promise","resolve","persistenceQueueRef","t4","t5","current","t6","signal","markHydrated","cancelled","loadCustomServers","t7","prev","length","persistedIds","Set","map","_temp","filter","r_0","has","r","id","hydrate","signal_0","t8","t10","t9","targetStorage","then","_temp2","_temp3","t11","t12","c_0","c","kind","name","url","icon","auth","cache","undefined","elicitation","onRemove","_temp4","connectorElements","t13","s_0","s","prev_0","x","customElements","serverElements","lookup","all","state","_temp5","_temp6","t14","servers","out","server","connectionState","tool","tools","fullName","type","description","parameters","inputSchema","execute","args","get","key","callTool","toolkit","clientRef","t15","client","modelContext","register","getModelContext","t16","t17","index","list","entry","Error","serverByKind","t18","t19","query","t20","t21","t22","index_0","t23","index_1","connectionTimeout_0","record","crypto","randomUUID","Date","now","Math","random","toString","slice","createdAt","prev_1","some","c_1","remove","clearAuthState","prev_2","s_3","t24","getState","connector","customServer","addCustomServer","removeServer","McpManagerResource","scopes","parent","source","s_1","s_2"],"sources":["../../src/resources/McpManagerResource.ts"],"sourcesContent":["import { useState, useEffect, useMemo, useEffectEvent, useRef } from \"react\";\nimport { useResource, resource, withKey } from \"@assistant-ui/tap\";\nimport {\n useClientLookup,\n useAssistantClientRef,\n attachTransformScopes,\n type ClientOutput,\n} from \"@assistant-ui/store\";\nimport { useAssistantScopeEffect } from \"@assistant-ui/store/client\";\nimport { ModelContext } from \"@assistant-ui/core/store\";\nimport type { Tool } from \"assistant-stream\";\nimport { McpServerResource } from \"./McpServerResource\";\nimport { McpLocalStorage } from \"./storage/McpLocalStorage\";\nimport type { MCPStorage, MCPStorageElement } from \"./storage/types\";\nimport { assertUniqueServerIds } from \"../utils/serverId\";\nimport type {\n MCPAuthConfig,\n MCPConnector,\n MCPCustomServerRecord,\n MCPManagerState,\n} from \"../mcp-scope\";\n\nexport type McpManagerResourceProps = {\n connectors?: MCPConnector[] | undefined;\n storage?: MCPStorageElement | undefined;\n /** OAuth redirect target. Defaults to `${origin}/mcp/callback`. */\n oauthRedirectUri?: string | undefined;\n /** Connect on mount when usable auth exists. Default true. */\n autoConnect?: boolean | undefined;\n /** Optional timeout in milliseconds for connect/listTools calls. Disabled by default. */\n connectionTimeout?: number | undefined;\n};\n\nfunction defaultRedirectUri(): string {\n if (typeof window === \"undefined\") return \"\";\n return `${window.location.origin}/mcp/callback`;\n}\n\n// Stable empty fallback so an absent `connectors` prop doesn't produce a fresh\n// array each render (which would invalidate the serverElements memo below).\nconst NO_CONNECTORS: MCPConnector[] = [];\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 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\nconst useMcpManagerResource = (\n props: McpManagerResourceProps,\n): ClientOutput<\"mcp\"> => {\n const connectors = props.connectors ?? NO_CONNECTORS;\n const autoConnect = props.autoConnect ?? true;\n const redirectUri = props.oauthRedirectUri ?? defaultRedirectUri();\n const connectionTimeout = props.connectionTimeout;\n\n const storageElement = props.storage ?? McpLocalStorage();\n const storage = useResource(storageElement);\n\n const [customServers, setCustomServers] = useState<MCPCustomServerRecord[]>(\n [],\n );\n const [isHydrated, setIsHydrated] = useState(false);\n\n const hydratedRef = useRef(false);\n const storageRef = useRef(storage);\n const persistenceQueueRef = useRef(Promise.resolve());\n\n useEffect(() => {\n storageRef.current = storage;\n }, [storage]);\n\n const hydrate = useEffectEvent(async (signal: { cancelled: boolean }) => {\n const markHydrated = () => {\n if (!signal.cancelled) {\n hydratedRef.current = true;\n setIsHydrated(true);\n }\n };\n\n let records: Awaited<ReturnType<typeof storage.loadCustomServers>>;\n try {\n records = await storage.loadCustomServers();\n } catch (error) {\n if (!signal.cancelled) {\n reportCustomStorageFailure(\"load\", error);\n }\n markHydrated();\n return;\n }\n\n if (signal.cancelled) return;\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 setCustomServers((prev) => {\n if (prev.length === 0) return records;\n const persistedIds = new Set(records.map((r) => r.id));\n return [...records, ...prev.filter((r) => !persistedIds.has(r.id))];\n });\n markHydrated();\n });\n\n useEffect(() => {\n const signal = { cancelled: false };\n void hydrate(signal);\n return () => {\n signal.cancelled = true;\n };\n }, []);\n\n useEffect(() => {\n if (!hydratedRef.current) return;\n const targetStorage = storageRef.current;\n persistenceQueueRef.current = persistenceQueueRef.current.then(() =>\n persistCustomServers(targetStorage, customServers),\n );\n }, [customServers]);\n\n const serverElements = useMemo(() => {\n assertUniqueServerIds([\n ...connectors.map((c) => c.id),\n ...customServers.map((s) => s.id),\n ]);\n\n const connectorElements = connectors.map((c) =>\n withKey(\n c.id,\n McpServerResource({\n id: c.id,\n kind: \"connector\",\n name: c.name,\n url: c.url,\n icon: c.icon,\n auth: c.auth,\n storage,\n redirectUri,\n autoConnect,\n connectionTimeout: c.connectionTimeout ?? connectionTimeout,\n ...(c.cache !== undefined ? { cache: c.cache } : {}),\n ...(c.elicitation !== undefined\n ? { elicitation: c.elicitation }\n : {}),\n onRemove: async () => {\n // connectors cannot be removed\n },\n }),\n ),\n );\n const customElements = customServers.map((s) =>\n withKey(\n s.id,\n McpServerResource({\n id: s.id,\n kind: \"custom\",\n name: s.name,\n url: s.url,\n auth: s.auth,\n storage,\n redirectUri,\n autoConnect,\n connectionTimeout: s.connectionTimeout ?? connectionTimeout,\n ...(s.cache !== undefined ? { cache: s.cache } : {}),\n ...(s.elicitation !== undefined\n ? { elicitation: s.elicitation }\n : {}),\n onRemove: async () => {\n setCustomServers((prev) => prev.filter((x) => x.id !== s.id));\n },\n }),\n ),\n );\n return [...connectorElements, ...customElements];\n }, [\n connectors,\n customServers,\n storage,\n redirectUri,\n autoConnect,\n connectionTimeout,\n ]);\n\n const lookup = useClientLookup(serverElements);\n\n const state = useMemo<MCPManagerState>(() => {\n const all = lookup.state;\n return {\n servers: all,\n connectors: all.filter((s) => s.kind === \"connector\"),\n customServers: all.filter((s) => s.kind === \"custom\"),\n isHydrated,\n };\n }, [lookup.state, isHydrated]);\n\n // ─── Auto-register MCP tools as frontend tools in modelContext ─────\n // Build the toolkit from connected servers; re-register when the visible\n // tool surface changes. Tool names are prefixed with the server id to\n // avoid collisions across connected servers — connector ids must not\n // contain `__` (enforced by `defineConnector`); `addCustomServer`\n // generates UUIDs that satisfy the constraint by construction.\n const toolkit = useMemo<Record<string, Tool<any, any>>>(() => {\n const out: Record<string, Tool<any, any>> = {};\n for (const server of state.servers) {\n if (server.connectionState !== \"connected\") continue;\n for (const tool of server.tools) {\n const fullName = `${server.id}__${tool.name}`;\n out[fullName] = {\n type: \"frontend\",\n ...(tool.description !== undefined\n ? { description: tool.description }\n : {}),\n parameters: tool.inputSchema as never,\n execute: (args) =>\n lookup.get({ key: server.id }).callTool(tool.name, args as unknown),\n };\n }\n }\n return out;\n }, [state, lookup]);\n\n const clientRef = useAssistantClientRef();\n\n useAssistantScopeEffect(\n \"modelContext\",\n () => {\n const client = clientRef.current;\n if (!client) return;\n return client.modelContext.register({\n getModelContext: () => ({ tools: toolkit }),\n });\n },\n [toolkit],\n );\n\n const serverByKind = (kind: \"connector\" | \"custom\", index: number) => {\n const list = kind === \"connector\" ? state.connectors : state.customServers;\n const entry = list[index];\n if (!entry) {\n throw new Error(\n `McpManagerResource: no ${kind} at index ${index} (length ${list.length})`,\n );\n }\n return lookup.get({ key: entry.id });\n };\n\n return {\n getState: () => state,\n server: (query) => {\n if (\"id\" in query) return lookup.get({ key: query.id });\n return serverByKind(query.kind, query.index);\n },\n connector: ({ index }) => serverByKind(\"connector\", index),\n customServer: ({ index }) => serverByKind(\"custom\", index),\n addCustomServer: async ({\n name,\n url,\n auth,\n connectionTimeout,\n cache,\n elicitation,\n }) => {\n const record: MCPCustomServerRecord = {\n id:\n typeof crypto !== \"undefined\" && \"randomUUID\" in crypto\n ? crypto.randomUUID()\n : `mcp-${Date.now()}-${Math.random().toString(36).slice(2)}`,\n name,\n url,\n auth: auth as MCPAuthConfig,\n connectionTimeout,\n ...(cache !== undefined ? { cache } : {}),\n ...(elicitation !== undefined ? { elicitation } : {}),\n createdAt: Date.now(),\n };\n setCustomServers((prev) => [...prev, record]);\n return record.id;\n },\n removeServer: async (id) => {\n // removeServer is custom-server only — connectors are app-defined\n // and not user-removable. Refuse rather than silently no-op.\n if (state.connectors.some((c) => c.id === id)) {\n throw new Error(\n `Cannot remove connector \"${id}\" — connectors are app-defined and not removable. Use a custom server id instead.`,\n );\n }\n // Delegate to McpServerResource.remove() which disconnects,\n // clears auth state, and unregisters from customServers in one\n // place. Fallback to manual cleanup if the lookup is empty\n // (server already gone).\n try {\n await lookup.get({ key: id }).remove();\n } catch {\n await storage.clearAuthState(id);\n setCustomServers((prev) => prev.filter((s) => s.id !== id));\n }\n },\n };\n};\n\nexport const McpManagerResource = resource(useMcpManagerResource);\n\n// Ensure modelContext exists as a sibling when the manager mounts. If an\n// ancestor (e.g. a chat runtime) already provides modelContext, this is a\n// no-op; otherwise it's auto-mounted alongside `mcp`.\nattachTransformScopes(useMcpManagerResource, (scopes, parent) => {\n if (!scopes.modelContext && parent.modelContext.source === null) {\n scopes.modelContext = ModelContext();\n }\n});\n"],"mappings":";;;;;;;;;;AAiCA,SAAS8B,qBAA6B;CACpC,IAAI,OAAOC,WAAW,aAAa,OAAO;CAC1C,OAAO,GAAGA,OAAOC,SAASC,OAAM;AAClC;AAIA,MAAMC,gBAAgC,CAAA;AAEtC,MAAMC,8BACJC,WACAC,UACG;CACHC,QAAQD,MACN,sCAAsCD,UAAS,mBAC/CC,KACF;AACF;AAEA,MAAME,uBAAuB,OAC3Bb,SACAc,YACG;CACH,IAAI;EACF,MAAMd,QAAQe,kBAAkBD,OAAO;CACzC,SAASH,OAAO;EACdF,2BAA2B,QAAQE,KAAK;CAC1C;AACF;AAEA,MAAMK,yBAAwBC,UAAA;CAAA,MAAAC,IAAAC,EAAA,EAAA;CAG5B,MAAApB,aAAmBkB,MAAKlB,cAALS;CACnB,MAAAN,cAAoBe,MAAKf,eAAL;CAA0B,IAAAkB;CAAA,IAAAF,EAAA,OAAAD,MAAAhB,kBAAA;EAC1BmB,KAAAH,MAAKhB,oBAAqBG,mBAAmB;EAACc,EAAA,KAAAD,MAAAhB;EAAAiB,EAAA,KAAAE;CAAA,OAAAA,KAAAF,EAAA;CAAlE,MAAAG,cAAoBD;CACpB,MAAAjB,oBAA0Bc,MAAKd;CAAmB,IAAAmB;CAAA,IAAAJ,EAAA,OAAAD,MAAAjB,SAAA;EAE3BsB,KAAAL,MAAKjB,WAAYV,gBAAgB;EAAC4B,EAAA,KAAAD,MAAAjB;EAAAkB,EAAA,KAAAI;CAAA,OAAAA,KAAAJ,EAAA;CACzD,MAAAlB,UAAgBrB,YAAY4C,EAAc;CAAE,IAAAC;CAAA,IAAAN,EAAA,OAAAO,OAAAC,IAAA,2BAAA,GAAA;EAG1CF,KAAA,CAAA;EAAEN,EAAA,KAAAM;CAAA,OAAAA,KAAAN,EAAA;CADJ,MAAA,CAAAS,eAAAC,oBAA0CtD,SACxCkD,EACF;CACA,MAAA,CAAAK,YAAAC,iBAAoCxD,SAAS,KAAK;CAElD,MAAAyD,cAAoBrD,OAAO,KAAK;CAChC,MAAAsD,aAAmBtD,OAAOsB,OAAO;CAAE,IAAAiC;CAAA,IAAAf,EAAA,OAAAO,OAAAC,IAAA,2BAAA,GAAA;EACAO,KAAAC,QAAOC,QAAS;EAACjB,EAAA,KAAAe;CAAA,OAAAA,KAAAf,EAAA;CAApD,MAAAkB,sBAA4B1D,OAAOuD,EAAiB;CAAE,IAAAI;CAAA,IAAAC;CAAA,IAAApB,EAAA,OAAAlB,SAAA;EAE5CqC,WAAA;GACRL,WAAUO,UAAWvC;EAAH;EACjBsC,KAAA,CAACtC,OAAO;EAACkB,EAAA,KAAAlB;EAAAkB,EAAA,KAAAmB;EAAAnB,EAAA,KAAAoB;CAAA,OAAA;EAAAD,KAAAnB,EAAA;EAAAoB,KAAApB,EAAA;CAAA;CAFZ3C,UAAU8D,IAEPC,EAAS;CAAC,IAAAE;CAAA,IAAAtB,EAAA,OAAAlB,SAAA;EAEkBwC,KAAA,OAAAC,WAAA;GAC7B,MAAAC,qBAAqB;IACnB,IAAI,CAACD,OAAME,WAAU;KACnBZ,YAAWQ,UAAW;KACtBT,cAAc,IAAI;IAAC;GACpB;GAGChB,IAAAA;GACJ,IAAA;IACEA,UAAUA,MAAMd,QAAO4C,kBAAmB;GAAnC,SAAAC,IAAA;IACAlC,MAAAA,QAAAA;IACP,IAAI,CAAC8B,OAAME,WACTlC,2BAA2B,QAAQE,KAAK;IAE1C+B,aAAa;IAAC;GAAA;GAIhB,IAAID,OAAME,WAAU;GAIpBf,kBAAiBkB,SAAA;IACf,IAAIA,KAAIC,WAAY,GAAC,OAASjC;IAC9B,MAAAkC,eAAqB,IAAIC,IAAInC,QAAOoC,IAAKC,KAAW,CAAC;IAAE,OAChD,CAAA,GAAIrC,SAAO,GAAKgC,KAAIM,QAAQC,QAAO,CAACL,aAAYM,IAAKC,IAACC,EAAG,CAAC,CAAC;GAAC,CACpE;GACDd,aAAa;EAAC;EACfxB,EAAA,KAAAlB;EAAAkB,EAAA,MAAAsB;CAAA,OAAAA,KAAAtB,EAAA;CA7BD,MAAAuC,UAAgBhF,eAAe+D,EA6B9B;CAAE,IAAAK;CAAA,IAAA3B,EAAA,QAAAuC,SAAA;EAEOZ,WAAA;GACR,MAAAa,WAAe,EAAAf,WAAa,MAAM;GAC7Bc,QAAQhB,QAAM;GAAC,aACb;IACLA,SAAME,YAAa;GAAH;EACjB;EACFzB,EAAA,MAAAuC;EAAAvC,EAAA,MAAA2B;CAAA,OAAAA,KAAA3B,EAAA;CAAA,IAAAyC;CAAA,IAAAzC,EAAA,QAAAO,OAAAC,IAAA,2BAAA,GAAA;EAAEiC,KAAA,CAAA;EAAEzC,EAAA,MAAAyC;CAAA,OAAAA,KAAAzC,EAAA;CANL3C,UAAUsE,IAMPc,EAAE;CAAC,IAAAC;CAAA,IAAAC;CAAA,IAAA3C,EAAA,QAAAS,eAAA;EAEIkC,WAAA;GACR,IAAI,CAAC9B,YAAWQ,SAAQ;GACxB,MAAAuB,gBAAsB9B,WAAUO;GAChCH,oBAAmBG,UAAWH,oBAAmBG,QAAQwB,WACvDlD,qBAAqBiD,eAAenC,aAAa,CACnD;EAF2B;EAG1BiC,MAAA,CAACjC,aAAa;EAACT,EAAA,MAAAS;EAAAT,EAAA,MAAA0C;EAAA1C,EAAA,MAAA2C;CAAA,OAAA;EAAAD,MAAA1C,EAAA;EAAA2C,KAAA3C,EAAA;CAAA;CANlB3C,UAAUsF,IAMPD,GAAe;CAGhBnE,sBAAsB,CAAA,GACjBM,WAAUmD,IAAKc,MAAW,GAAC,GAC3BrC,cAAauB,IAAKe,MAAW,CAAC,CAClC;CAAC,IAAAC;CAAA,IAAAhD,EAAA,QAAAhB,eAAAgB,EAAA,QAAAf,qBAAAe,EAAA,QAAAnB,cAAAmB,EAAA,QAAAS,iBAAAT,EAAA,QAAAG,eAAAH,EAAA,QAAAlB,SAAA;EAAA,IAAAmE;EAAA,IAAAjD,EAAA,QAAAhB,eAAAgB,EAAA,QAAAf,qBAAAe,EAAA,QAAAG,eAAAH,EAAA,QAAAlB,SAAA;GAEuCmE,OAAAC,QACvCvF,QACEwF,IAACb,IACDnE,kBAAkB;IAAAmE,IACZa,IAACb;IAAGc,MACF;IAAWC,MACXF,IAACE;IAAKC,KACPH,IAACG;IAAIC,MACJJ,IAACI;IAAKC,MACNL,IAACK;IAAK1E;IAAAqB;IAAAnB;IAAAC,mBAIOkE,IAAClE,qBAADA;IAAwC,GACvDkE,IAACM,UAAWC,KAAAA,IAAZ,EAAAD,OAAiCN,IAACM,MAAY,IAA9C,CAA8C;IAAC,GAC/CN,IAACQ,gBAAiBD,KAAAA,IAAlB,EAAAC,aACeR,IAACQ,YACf,IAFD,CAEC;IAACC,UACIC;GAGZ,CAAC,CACH;GAAC7D,EAAA,MAAAhB;GAAAgB,EAAA,MAAAf;GAAAe,EAAA,MAAAG;GAAAH,EAAA,MAAAlB;GAAAkB,EAAA,MAAAiD;EAAA,OAAAA,MAAAjD,EAAA;EAtBH,MAAA8D,oBAA0BjF,WAAUmD,IAAKiB,GAuBzC;EAAE,IAAAc;EAAA,IAAA/D,EAAA,QAAAhB,eAAAgB,EAAA,QAAAf,qBAAAe,EAAA,QAAAG,eAAAH,EAAA,QAAAlB,SAAA;GACuCiF,OAAAC,QACvCrG,QACEsG,IAAC3B,IACDnE,kBAAkB;IAAAmE,IACZ2B,IAAC3B;IAAGc,MACF;IAAQC,MACRY,IAACZ;IAAKC,KACPW,IAACX;IAAIE,MACJS,IAACT;IAAK1E;IAAAqB;IAAAnB;IAAAC,mBAIOgF,IAAChF,qBAADA;IAAwC,GACvDgF,IAACR,UAAWC,KAAAA,IAAZ,EAAAD,OAAiCQ,IAACR,MAAY,IAA9C,CAA8C;IAAC,GAC/CQ,IAACN,gBAAiBD,KAAAA,IAAlB,EAAAC,aACeM,IAACN,YACf,IAFD,CAEC;IAACC,UACI,YAAA;KACRlD,kBAAiBwD,WAAUtC,OAAIM,QAAQiC,MAAOA,EAAC7B,OAAQ2B,IAAC3B,EAAG,CAAC;IAAC;GAEjE,CAAC,CACH;GAACtC,EAAA,MAAAhB;GAAAgB,EAAA,MAAAf;GAAAe,EAAA,MAAAG;GAAAH,EAAA,MAAAlB;GAAAkB,EAAA,MAAA+D;EAAA,OAAAA,MAAA/D,EAAA;EArBH,MAAAoE,iBAAuB3D,cAAauB,IAAK+B,GAsBzC;EACOf,MAAA,CAAA,GAAIc,mBAAiB,GAAKM,cAAc;EAACpE,EAAA,MAAAhB;EAAAgB,EAAA,MAAAf;EAAAe,EAAA,MAAAnB;EAAAmB,EAAA,MAAAS;EAAAT,EAAA,MAAAG;EAAAH,EAAA,MAAAlB;EAAAkB,EAAA,MAAAgD;CAAA,OAAAA,MAAAhD,EAAA;CAUlD,MAAAsE,SAAe1G,gBAAgByG,GAAc;CAG3C,MAAAE,MAAYD,OAAME;CAAO,IAAAvB;CAAA,IAAAjD,EAAA,QAAAuE,KAAA;EAGXtB,MAAAsB,IAAGrC,OAAQuC,MAA6B;EAACzE,EAAA,MAAAuE;EAAAvE,EAAA,MAAAiD;CAAA,OAAAA,MAAAjD,EAAA;CAAA,IAAA+D;CAAA,IAAA/D,EAAA,QAAAuE,KAAA;EACtCR,MAAAQ,IAAGrC,OAAQwC,MAA0B;EAAC1E,EAAA,MAAAuE;EAAAvE,EAAA,MAAA+D;CAAA,OAAAA,MAAA/D,EAAA;CAAA,IAAA2E;CAAA,IAAA3E,EAAA,QAAAuE,OAAAvE,EAAA,QAAAW,cAAAX,EAAA,QAAAiD,OAAAjD,EAAA,QAAA+D,KAAA;EAHhDY,MAAA;GAAAC,SACIL;GAAG1F,YACAoE;GAAyCxC,eACtCsD;GAAsCpD;EAEvD;EAACX,EAAA,MAAAuE;EAAAvE,EAAA,MAAAW;EAAAX,EAAA,MAAAiD;EAAAjD,EAAA,MAAA+D;EAAA/D,EAAA,MAAA2E;CAAA,OAAAA,MAAA3E,EAAA;CAPH,MAAAwE,QAEEG;CAM6B,IAAAE;CAAA,IAAA7E,EAAA,QAAAsE,UAAAtE,EAAA,QAAAwE,MAAAI,SAAA;EAS7BC,MAA4C,CAAC;EAC7C,KAAK,MAAAC,UAAgBN,MAAKI,SAAQ;GAChC,IAAIE,OAAMC,oBAAqB,aAAa;GAC5C,KAAK,MAAAC,QAAcF,OAAMG,OAAM;IAC7B,MAAAC,WAAiB,GAAGJ,OAAMxC,GAAG,IAAK0C,KAAI3B;IACtCwB,IAAIK,YAAY;KAAAC,MACR;KAAU,GACZH,KAAII,gBAAiB1B,KAAAA,IAArB,EAAA0B,aACeJ,KAAII,YAClB,IAFD,CAEC;KAACC,YACML,KAAIM;KAAqBC,UAC5BC,SACPlB,OAAMmB,IAAK,EAAAC,KAAOZ,OAAMxC,GAAI,CAAC,CAAC,CAAAqD,SAAUX,KAAI3B,MAAOmC,IAAe;IACtE;GARa;EASd;EACFxF,EAAA,MAAAsE;EAAAtE,EAAA,MAAAwE,MAAAI;EAAA5E,EAAA,MAAA6E;CAAA,OAAAA,MAAA7E,EAAA;CAhBH,MAAA4F,UAiBEf;CAGF,MAAAgB,YAAkBhI,sBAAsB;CAAE,IAAAiI;CAAA,IAAA9F,EAAA,QAAA6F,aAAA7F,EAAA,QAAA4F,SAAA;EAIxCE,YAAA;GACE,MAAAC,SAAeF,UAASxE;GACxB,IAAI,CAAC0E,QAAM;GAAS,OACbA,OAAMC,aAAaC,SAAU,EAAAC,wBACV,EAAAjB,OAASW,QAAQ,GAC3C,CAAC;EAAC;EACH5F,EAAA,MAAA6F;EAAA7F,EAAA,MAAA4F;EAAA5F,EAAA,MAAA8F;CAAA,OAAAA,MAAA9F,EAAA;CAAA,IAAAmG;CAAA,IAAAnG,EAAA,QAAA4F,SAAA;EACDO,MAAA,CAACP,OAAO;EAAC5F,EAAA,MAAA4F;EAAA5F,EAAA,MAAAmG;CAAA,OAAAA,MAAAnG,EAAA;CATXhC,wBACE,gBACA8H,KAOAK,GACF;CAAC,IAAAC;CAAA,IAAApG,EAAA,QAAAsE,UAAAtE,EAAA,QAAAwE,OAAA;EAEoB4B,OAAAhD,MAAAiD,UAAA;GACnB,MAAAC,OAAalD,SAAS,cAAcoB,MAAK3F,aAAc2F,MAAK/D;GAC5D,MAAA8F,QAAcD,KAAKD;GACnB,IAAI,CAACE,OACH,MAAM,IAAIC,MACR,0BAA0BpD,KAAI,YAAaiD,MAAK,WAAYC,KAAIzE,OAAO,EACzE;GACD,OACMyC,OAAMmB,IAAK,EAAAC,KAAOa,MAAKjE,GAAI,CAAC;EAAC;EACrCtC,EAAA,MAAAsE;EAAAtE,EAAA,MAAAwE;EAAAxE,EAAA,MAAAoG;CAAA,OAAAA,MAAApG,EAAA;CATD,MAAAyG,eAAqBL;CASnB,IAAAM;CAAA,IAAA1G,EAAA,QAAAwE,OAAA;EAGUkC,YAAMlC;EAAKxE,EAAA,MAAAwE;EAAAxE,EAAA,MAAA0G;CAAA,OAAAA,MAAA1G,EAAA;CAAA,IAAA2G;CAAA,IAAA3G,EAAA,QAAAsE,UAAAtE,EAAA,QAAAyG,cAAA;EACbE,OAAAC,UAAA;GACN,IAAI,QAAQA,OAAK,OAAStC,OAAMmB,IAAK,EAAAC,KAAOkB,MAAKtE,GAAI,CAAC;GAAE,OACjDmE,aAAaG,MAAKxD,MAAOwD,MAAKP,KAAM;EAAC;EAC7CrG,EAAA,MAAAsE;EAAAtE,EAAA,MAAAyG;EAAAzG,EAAA,MAAA2G;CAAA,OAAAA,MAAA3G,EAAA;CAAA,IAAA6G;CAAA,IAAAC;CAAA,IAAA9G,EAAA,QAAAyG,cAAA;EACUI,OAAAE,QAAA;GAAC,MAAA,EAAAV,OAAAW,YAAAD;GAAS,OAAKN,aAAa,aAAaJ,OAAK;EAAC;EAC5CS,OAAAG,QAAA;GAAC,MAAA,EAAAZ,OAAAa,YAAAD;GAAS,OAAKR,aAAa,UAAUJ,OAAK;EAAC;EAAArG,EAAA,MAAAyG;EAAAzG,EAAA,MAAA6G;EAAA7G,EAAA,MAAA8G;CAAA,OAAA;EAAAD,MAAA7G,EAAA;EAAA8G,MAAA9G,EAAA;CAAA;CAAA,IAAA+G;CAAA,IAAA/G,EAAA,QAAAO,OAAAC,IAAA,2BAAA,GAAA;EACzCuG,MAAA,OAAAE,QAAA;GAAO,MAAA,EAAA5D,MAAAC,KAAAE,MAAAvE,mBAAAkI,qBAAA1D,OAAAE,gBAAAsD;GAQtB,MAAAG,SAAsC;IAAA9E,IAElC,OAAO+E,WAAW,eAAe,gBAAgBA,SAC7CA,OAAMC,WACmD,IAF7D,OAEWC,KAAIC,IAAK,EAAC,GAAIC,KAAIC,OAAQ,CAAC,CAAAC,SAAU,EAAE,CAAC,CAAAC,MAAO,CAAC;IAAGvE;IAAAC;IAG1DE;IAAqBvE,mBAC3BA;IAAiB,GACbwE,UAAUC,KAAAA,IAAV,EAAAD,MAAmC,IAAnC,CAAmC;IAAC,GACpCE,gBAAgBD,KAAAA,IAAhB,EAAAC,YAA+C,IAA/C,CAA+C;IAACkE,WACzCN,KAAIC,IAAK;GACtB;GACA9G,kBAAiBoH,WAAU,CAAA,GAAIlG,QAAMwF,MAAM,CAAC;GAAC,OACtCA,OAAM9E;EAAG;EACjBtC,EAAA,MAAA+G;CAAA,OAAAA,MAAA/G,EAAA;CAAA,IAAAiH;CAAA,IAAAjH,EAAA,QAAAsE,UAAAtE,EAAA,QAAAwE,SAAAxE,EAAA,QAAAlB,SAAA;EACamI,MAAA,OAAA3E,OAAA;GAGZ,IAAIkC,MAAK3F,WAAWkJ,MAAMC,QAAO7E,IAACb,OAAQA,EAAE,GAC1C,MAAM,IAAIkE,MACR,4BAA4BlE,GAAE,kFAChC;GAMF,IAAA;IACE,MAAMgC,OAAMmB,IAAK,EAAAC,KAAOpD,GAAG,CAAC,CAAC,CAAA2F,OAAQ;GAAC,QAAA;IAEtC,MAAMnJ,QAAOoJ,eAAgB5F,EAAE;IAC/B5B,kBAAiByH,WAAUvG,OAAIM,QAAQkG,QAAOnE,IAAC3B,OAAQA,EAAE,CAAC;GAAC;EAC5D;EACFtC,EAAA,MAAAsE;EAAAtE,EAAA,MAAAwE;EAAAxE,EAAA,MAAAlB;EAAAkB,EAAA,MAAAiH;CAAA,OAAAA,MAAAjH,EAAA;CAAA,IAAAqI;CAAA,IAAArI,EAAA,QAAA0G,OAAA1G,EAAA,QAAA2G,OAAA3G,EAAA,QAAA6G,OAAA7G,EAAA,QAAA8G,OAAA9G,EAAA,QAAAiH,KAAA;EAlDIoB,MAAA;GAAAC,UACK5B;GAAW5B,QACb6B;GAGP4B,WACU1B;GAA+C2B,cAC5C1B;GAA4C2B,iBACzC1B;GAuBhB2B,cACazB;EAmBhB;EAACjH,EAAA,MAAA0G;EAAA1G,EAAA,MAAA2G;EAAA3G,EAAA,MAAA6G;EAAA7G,EAAA,MAAA8G;EAAA9G,EAAA,MAAAiH;EAAAjH,EAAA,MAAAqI;CAAA,OAAAA,MAAArI,EAAA;CAAA,OAnDMqI;AAmDN;AAGH,MAAaM,qBAAqBjL,SAASoC,qBAAqB;AAKhEhC,sBAAsBgC,wBAAwB8I,QAAQC,WAAW;CAC/D,IAAI,CAACD,OAAO5C,gBAAgB6C,OAAO7C,aAAa8C,WAAW,MACzDF,OAAO5C,eAAe/H,aAAa;AAEvC,CAAC;AApQ6B,SAAAgE,MAAAI,GAAA;CAAA,OAiDwBA,EAACC;AAAG;AAjD5B,SAAAQ,OAAAK,GAAA;CAAA,OAyECA,EAACb;AAAG;AAzEL,SAAAS,OAAAkB,GAAA;CAAA,OA0EIA,EAAC3B;AAAG;AA1ER,eAAAuB,SAAA,CAAA;AAAA,SAAAY,OAAAsE,KAAA;CAAA,OA4IM9E,IAACb,SAAU;AAAW;AA5I5B,SAAAsB,OAAAsE,KAAA;CAAA,OA6IS/E,IAACb,SAAU;AAAQ"}
1
+ {"version":3,"file":"McpManagerResource.js","names":["useState","useEffect","useMemo","useEffectEvent","useRef","useResource","resource","withKey","useClientLookup","useAssistantClientRef","attachTransformScopes","ClientOutput","useAssistantScopeEffect","ModelContext","createMcpId","clearOAuthProviderAuthState","Tool","McpServerResource","McpLocalStorage","MCPStorage","MCPStorageElement","assertUniqueServerIds","MCPAuthConfig","MCPConnector","MCPCustomServerRecord","MCPManagerState","McpManagerResourceProps","connectors","storage","oauthRedirectUri","autoConnect","connectionTimeout","defaultRedirectUri","window","location","origin","NO_CONNECTORS","reportCustomStorageFailure","operation","error","console","persistCustomServers","records","saveCustomServers","useMcpManagerResource","props","$","_c","t0","redirectUri","t1","storageElement","t2","Symbol","for","customServers","setCustomServers","isHydrated","setIsHydrated","hydratedRef","storageRef","t3","Promise","resolve","persistenceQueueRef","t4","t5","current","t6","signal","markHydrated","cancelled","loadCustomServers","t7","prev","length","persistedIds","Set","map","_temp","filter","r_0","has","r","id","hydrate","signal_0","t8","t10","t9","targetStorage","then","_temp2","_temp3","t11","t12","c_0","c","kind","name","url","icon","auth","cache","undefined","elicitation","onRemove","_temp4","connectorElements","t13","s_0","s","prev_0","x","customElements","serverElements","lookup","all","state","_temp5","_temp6","t14","servers","out","server","connectionState","tool","tools","fullName","type","description","parameters","inputSchema","execute","args","get","key","callTool","toolkit","clientRef","t15","client","modelContext","register","getModelContext","t16","t17","index","list","entry","Error","serverByKind","t18","t19","query","t20","t21","t22","index_0","t23","index_1","connectionTimeout_0","record","createdAt","Date","now","prev_1","some","c_1","remove","prev_2","s_3","t24","getState","connector","customServer","addCustomServer","removeServer","McpManagerResource","scopes","parent","source","s_1","s_2"],"sources":["../../src/resources/McpManagerResource.ts"],"sourcesContent":["import { useState, useEffect, useMemo, useEffectEvent, useRef } from \"react\";\nimport { useResource, resource, withKey } from \"@assistant-ui/tap\";\nimport {\n useClientLookup,\n useAssistantClientRef,\n attachTransformScopes,\n type ClientOutput,\n} from \"@assistant-ui/store\";\nimport { useAssistantScopeEffect } from \"@assistant-ui/store/client\";\nimport { ModelContext } from \"@assistant-ui/core/store\";\nimport { createMcpId } from \"../utils/createMcpId\";\nimport { clearOAuthProviderAuthState } from \"../auth/createOAuthProvider\";\nimport type { Tool } from \"assistant-stream\";\nimport { McpServerResource } from \"./McpServerResource\";\nimport { McpLocalStorage } from \"./storage/McpLocalStorage\";\nimport type { MCPStorage, MCPStorageElement } from \"./storage/types\";\nimport { assertUniqueServerIds } from \"../utils/serverId\";\nimport type {\n MCPAuthConfig,\n MCPConnector,\n MCPCustomServerRecord,\n MCPManagerState,\n} from \"../mcp-scope\";\n\nexport type McpManagerResourceProps = {\n connectors?: MCPConnector[] | undefined;\n storage?: MCPStorageElement | undefined;\n /** OAuth redirect target. Defaults to `${origin}/mcp/callback`. */\n oauthRedirectUri?: string | undefined;\n /** Connect on mount when usable auth exists. Default true. */\n autoConnect?: boolean | undefined;\n /** Optional timeout in milliseconds for connect/listTools calls. Disabled by default. */\n connectionTimeout?: number | undefined;\n};\n\nfunction defaultRedirectUri(): string {\n if (typeof window === \"undefined\") return \"\";\n return `${window.location.origin}/mcp/callback`;\n}\n\n// Stable empty fallback so an absent `connectors` prop doesn't produce a fresh\n// array each render (which would invalidate the serverElements memo below).\nconst NO_CONNECTORS: MCPConnector[] = [];\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 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\nconst useMcpManagerResource = (\n props: McpManagerResourceProps,\n): ClientOutput<\"mcp\"> => {\n const connectors = props.connectors ?? NO_CONNECTORS;\n const autoConnect = props.autoConnect ?? true;\n const redirectUri = props.oauthRedirectUri ?? defaultRedirectUri();\n const connectionTimeout = props.connectionTimeout;\n\n const storageElement = props.storage ?? McpLocalStorage();\n const storage = useResource(storageElement);\n\n const [customServers, setCustomServers] = useState<MCPCustomServerRecord[]>(\n [],\n );\n const [isHydrated, setIsHydrated] = useState(false);\n\n const hydratedRef = useRef(false);\n const storageRef = useRef(storage);\n const persistenceQueueRef = useRef(Promise.resolve());\n\n useEffect(() => {\n storageRef.current = storage;\n }, [storage]);\n\n const hydrate = useEffectEvent(async (signal: { cancelled: boolean }) => {\n const markHydrated = () => {\n if (!signal.cancelled) {\n hydratedRef.current = true;\n setIsHydrated(true);\n }\n };\n\n let records: Awaited<ReturnType<typeof storage.loadCustomServers>>;\n try {\n records = await storage.loadCustomServers();\n } catch (error) {\n if (!signal.cancelled) {\n reportCustomStorageFailure(\"load\", error);\n }\n markHydrated();\n return;\n }\n\n if (signal.cancelled) return;\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 setCustomServers((prev) => {\n if (prev.length === 0) return records;\n const persistedIds = new Set(records.map((r) => r.id));\n return [...records, ...prev.filter((r) => !persistedIds.has(r.id))];\n });\n markHydrated();\n });\n\n useEffect(() => {\n const signal = { cancelled: false };\n void hydrate(signal);\n return () => {\n signal.cancelled = true;\n };\n }, []);\n\n useEffect(() => {\n if (!hydratedRef.current) return;\n const targetStorage = storageRef.current;\n persistenceQueueRef.current = persistenceQueueRef.current.then(() =>\n persistCustomServers(targetStorage, customServers),\n );\n }, [customServers]);\n\n const serverElements = useMemo(() => {\n assertUniqueServerIds([\n ...connectors.map((c) => c.id),\n ...customServers.map((s) => s.id),\n ]);\n\n const connectorElements = connectors.map((c) =>\n withKey(\n c.id,\n McpServerResource({\n id: c.id,\n kind: \"connector\",\n name: c.name,\n url: c.url,\n icon: c.icon,\n auth: c.auth,\n storage,\n redirectUri,\n autoConnect,\n connectionTimeout: c.connectionTimeout ?? connectionTimeout,\n ...(c.cache !== undefined ? { cache: c.cache } : {}),\n ...(c.elicitation !== undefined\n ? { elicitation: c.elicitation }\n : {}),\n onRemove: async () => {\n // connectors cannot be removed\n },\n }),\n ),\n );\n const customElements = customServers.map((s) =>\n withKey(\n s.id,\n McpServerResource({\n id: s.id,\n kind: \"custom\",\n name: s.name,\n url: s.url,\n auth: s.auth,\n storage,\n redirectUri,\n autoConnect,\n connectionTimeout: s.connectionTimeout ?? connectionTimeout,\n ...(s.cache !== undefined ? { cache: s.cache } : {}),\n ...(s.elicitation !== undefined\n ? { elicitation: s.elicitation }\n : {}),\n onRemove: async () => {\n setCustomServers((prev) => prev.filter((x) => x.id !== s.id));\n },\n }),\n ),\n );\n return [...connectorElements, ...customElements];\n }, [\n connectors,\n customServers,\n storage,\n redirectUri,\n autoConnect,\n connectionTimeout,\n ]);\n\n const lookup = useClientLookup(serverElements);\n\n const state = useMemo<MCPManagerState>(() => {\n const all = lookup.state;\n return {\n servers: all,\n connectors: all.filter((s) => s.kind === \"connector\"),\n customServers: all.filter((s) => s.kind === \"custom\"),\n isHydrated,\n };\n }, [lookup.state, isHydrated]);\n\n // ─── Auto-register MCP tools as frontend tools in modelContext ─────\n // Build the toolkit from connected servers; re-register when the visible\n // tool surface changes. Tool names are prefixed with the server id to\n // avoid collisions across connected servers — connector ids must not\n // contain `__` (enforced by `defineConnector`); `addCustomServer`\n // generates UUIDs that satisfy the constraint by construction.\n const toolkit = useMemo<Record<string, Tool<any, any>>>(() => {\n const out: Record<string, Tool<any, any>> = {};\n for (const server of state.servers) {\n if (server.connectionState !== \"connected\") continue;\n for (const tool of server.tools) {\n const fullName = `${server.id}__${tool.name}`;\n out[fullName] = {\n type: \"frontend\",\n ...(tool.description !== undefined\n ? { description: tool.description }\n : {}),\n parameters: tool.inputSchema as never,\n execute: (args) =>\n lookup.get({ key: server.id }).callTool(tool.name, args as unknown),\n };\n }\n }\n return out;\n }, [state, lookup]);\n\n const clientRef = useAssistantClientRef();\n\n useAssistantScopeEffect(\n \"modelContext\",\n () => {\n const client = clientRef.current;\n if (!client) return;\n return client.modelContext.register({\n getModelContext: () => ({ tools: toolkit }),\n });\n },\n [toolkit],\n );\n\n const serverByKind = (kind: \"connector\" | \"custom\", index: number) => {\n const list = kind === \"connector\" ? state.connectors : state.customServers;\n const entry = list[index];\n if (!entry) {\n throw new Error(\n `McpManagerResource: no ${kind} at index ${index} (length ${list.length})`,\n );\n }\n return lookup.get({ key: entry.id });\n };\n\n return {\n getState: () => state,\n server: (query) => {\n if (\"id\" in query) return lookup.get({ key: query.id });\n return serverByKind(query.kind, query.index);\n },\n connector: ({ index }) => serverByKind(\"connector\", index),\n customServer: ({ index }) => serverByKind(\"custom\", index),\n addCustomServer: async ({\n name,\n url,\n auth,\n connectionTimeout,\n cache,\n elicitation,\n }) => {\n const record: MCPCustomServerRecord = {\n id: createMcpId(),\n name,\n url,\n auth: auth as MCPAuthConfig,\n connectionTimeout,\n ...(cache !== undefined ? { cache } : {}),\n ...(elicitation !== undefined ? { elicitation } : {}),\n createdAt: Date.now(),\n };\n setCustomServers((prev) => [...prev, record]);\n return record.id;\n },\n removeServer: async (id) => {\n // removeServer is custom-server only — connectors are app-defined\n // and not user-removable. Refuse rather than silently no-op.\n if (state.connectors.some((c) => c.id === id)) {\n throw new Error(\n `Cannot remove connector \"${id}\" — connectors are app-defined and not removable. Use a custom server id instead.`,\n );\n }\n // Delegate to McpServerResource.remove() which disconnects,\n // clears auth state, and unregisters from customServers in one\n // place. Fallback to manual cleanup if the lookup is empty\n // (server already gone).\n try {\n await lookup.get({ key: id }).remove();\n } catch {\n await clearOAuthProviderAuthState(storage, id);\n setCustomServers((prev) => prev.filter((s) => s.id !== id));\n }\n },\n };\n};\n\nexport const McpManagerResource = resource(useMcpManagerResource);\n\n// Ensure modelContext exists as a sibling when the manager mounts. If an\n// ancestor (e.g. a chat runtime) already provides modelContext, this is a\n// no-op; otherwise it's auto-mounted alongside `mcp`.\nattachTransformScopes(useMcpManagerResource, (scopes, parent) => {\n if (!scopes.modelContext && parent.modelContext.source === null) {\n scopes.modelContext = ModelContext();\n }\n});\n"],"mappings":"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"}
@@ -19,7 +19,8 @@ type McpServerResourceProps = {
19
19
  readonly elicitation?: boolean;
20
20
  onRemove: () => Promise<void>;
21
21
  };
22
+ declare const getConnectionDependencies: (props: McpServerResourceProps) => readonly unknown[];
22
23
  declare const McpServerResource: import("@assistant-ui/tap").Resource<ClientOutput<"mcpServer">, [props: McpServerResourceProps]>;
23
24
  //#endregion
24
- export { McpServerResource, McpServerResourceProps };
25
+ export { McpServerResource, McpServerResourceProps, getConnectionDependencies };
25
26
  //# sourceMappingURL=McpServerResource.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"McpServerResource.d.ts","names":[],"sources":["../../src/resources/McpServerResource.ts"],"mappings":";;;;KA2BY;EACV;EACA,MAAM;EACN;EACA;EACA;EACA,MAAM;EACN,SAAS;EACT;EACA;EACA;EACA;aAAmB;;WACV;EACT,gBAAgB;;cA0lBL,+CAAiB,SAAA,4BAAA,OAAA"}
1
+ {"version":3,"file":"McpServerResource.d.ts","names":[],"sources":["../../src/resources/McpServerResource.ts"],"mappings":";;;;KA+BY;EACV;EACA,MAAM;EACN;EACA;EACA;EACA,MAAM;EACN,SAAS;EACT;EACA;EACA;EACA;aAAmB;;WACV;EACT,gBAAgB;;cAOL,4BACX,OAAO;cA+qBI,+CAAiB,SAAA,4BAAA,OAAA"}