@assistant-ui/react-mcp 0.1.16 → 0.1.18

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 (61) hide show
  1. package/dist/auth/createOAuthProvider.d.ts +13 -2
  2. package/dist/auth/createOAuthProvider.d.ts.map +1 -1
  3. package/dist/auth/createOAuthProvider.js +109 -31
  4. package/dist/auth/createOAuthProvider.js.map +1 -1
  5. package/dist/auth/types.d.ts +5 -1
  6. package/dist/auth/types.d.ts.map +1 -1
  7. package/dist/primitives/addForm/McpAddFormAuthFields.js +71 -28
  8. package/dist/primitives/addForm/McpAddFormAuthFields.js.map +1 -1
  9. package/dist/primitives/addForm/McpAddFormError.d.ts.map +1 -1
  10. package/dist/primitives/addForm/McpAddFormError.js +30 -10
  11. package/dist/primitives/addForm/McpAddFormError.js.map +1 -1
  12. package/dist/primitives/addForm/McpAddFormNameField.js +31 -18
  13. package/dist/primitives/addForm/McpAddFormNameField.js.map +1 -1
  14. package/dist/primitives/addForm/McpAddFormRoot.d.ts.map +1 -1
  15. package/dist/primitives/addForm/McpAddFormRoot.js +32 -11
  16. package/dist/primitives/addForm/McpAddFormRoot.js.map +1 -1
  17. package/dist/primitives/addForm/McpAddFormUrlField.js +31 -18
  18. package/dist/primitives/addForm/McpAddFormUrlField.js.map +1 -1
  19. package/dist/primitives/addForm/context.d.ts +9 -1
  20. package/dist/primitives/addForm/context.d.ts.map +1 -1
  21. package/dist/primitives/addForm/context.js.map +1 -1
  22. package/dist/resources/McpManagerResource.d.ts.map +1 -1
  23. package/dist/resources/McpManagerResource.js +330 -247
  24. package/dist/resources/McpManagerResource.js.map +1 -1
  25. package/dist/resources/McpServerRemovalFence.d.ts +7 -0
  26. package/dist/resources/McpServerRemovalFence.d.ts.map +1 -0
  27. package/dist/resources/McpServerRemovalFence.js +11 -0
  28. package/dist/resources/McpServerRemovalFence.js.map +1 -0
  29. package/dist/resources/McpServerResource.d.ts.map +1 -1
  30. package/dist/resources/McpServerResource.js +41 -16
  31. package/dist/resources/McpServerResource.js.map +1 -1
  32. package/dist/resources/storage/McpLocalStorage.d.ts.map +1 -1
  33. package/dist/resources/storage/McpLocalStorage.js +16 -1
  34. package/dist/resources/storage/McpLocalStorage.js.map +1 -1
  35. package/dist/resources/storage/types.d.ts +10 -8
  36. package/dist/resources/storage/types.d.ts.map +1 -1
  37. package/dist/utils/serverUrl.d.ts +8 -0
  38. package/dist/utils/serverUrl.d.ts.map +1 -0
  39. package/dist/utils/serverUrl.js +15 -0
  40. package/dist/utils/serverUrl.js.map +1 -0
  41. package/package.json +7 -7
  42. package/src/auth/createOAuthProvider.test.ts +544 -35
  43. package/src/auth/createOAuthProvider.ts +201 -46
  44. package/src/auth/types.ts +5 -1
  45. package/src/primitives/addForm/McpAddFormAccessibility.test.tsx +261 -0
  46. package/src/primitives/addForm/McpAddFormAuthFields.tsx +33 -15
  47. package/src/primitives/addForm/McpAddFormError.tsx +17 -3
  48. package/src/primitives/addForm/McpAddFormNameField.tsx +13 -1
  49. package/src/primitives/addForm/McpAddFormRoot.tsx +51 -8
  50. package/src/primitives/addForm/McpAddFormUrlField.tsx +12 -1
  51. package/src/primitives/addForm/context.tsx +10 -0
  52. package/src/resources/McpManagerResource.test.ts +712 -9
  53. package/src/resources/McpManagerResource.ts +208 -56
  54. package/src/resources/McpServerRemovalFence.ts +21 -0
  55. package/src/resources/McpServerResource.test.ts +252 -17
  56. package/src/resources/McpServerResource.ts +40 -15
  57. package/src/resources/storage/McpLocalStorage.test.ts +28 -0
  58. package/src/resources/storage/McpLocalStorage.ts +23 -1
  59. package/src/resources/storage/types.ts +10 -8
  60. package/src/utils/serverUrl.test.ts +66 -0
  61. package/src/utils/serverUrl.ts +23 -0
@@ -1,10 +1,11 @@
1
1
  import { MCPAuthConfig } from "../mcp-scope.js";
2
2
  import { MCPStorage } from "../resources/storage/types.js";
3
- import { OAuthClientProvider } from "@modelcontextprotocol/client";
3
+ import { OAuthClientInformationFull, OAuthClientProvider, OAuthTokens } from "@modelcontextprotocol/client";
4
4
  //#region src/auth/createOAuthProvider.d.ts
5
5
  declare function decodeServerIdFromState(state: string): string | null;
6
6
  type CreateOAuthProviderOptions = {
7
7
  serverId: string;
8
+ serverUrl: string;
8
9
  /** Must be `auth.type === "oauth"`. */
9
10
  config: Extract<MCPAuthConfig, {
10
11
  type: "oauth";
@@ -14,6 +15,16 @@ type CreateOAuthProviderOptions = {
14
15
  /** Called by the SDK to start the authorization redirect. */
15
16
  onAuthorizationUrl: (url: URL) => void;
16
17
  };
18
+ type OAuthConfig = Extract<MCPAuthConfig, {
19
+ type: "oauth";
20
+ }>;
21
+ type OAuthCredentialState = {
22
+ tokens?: OAuthTokens | undefined;
23
+ tokensClientId?: string | undefined;
24
+ clientInformation?: OAuthClientInformationFull | undefined;
25
+ clientInformationSource?: "registered" | undefined;
26
+ };
27
+ declare const hasUsableOAuthTokens: (state: OAuthCredentialState | null | undefined, config: OAuthConfig) => boolean;
17
28
  /**
18
29
  * Clears persisted OAuth state after the in-flight load and every queued write
19
30
  * for that server have settled, so a discarded provider cannot recreate the
@@ -27,5 +38,5 @@ declare const clearOAuthProviderAuthState: (storage: MCPStorage, serverId: strin
27
38
  */
28
39
  declare function createOAuthProvider(opts: CreateOAuthProviderOptions): OAuthClientProvider;
29
40
  //#endregion
30
- export { CreateOAuthProviderOptions, clearOAuthProviderAuthState, createOAuthProvider, decodeServerIdFromState };
41
+ export { CreateOAuthProviderOptions, clearOAuthProviderAuthState, createOAuthProvider, decodeServerIdFromState, hasUsableOAuthTokens };
31
42
  //# 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;;;;;;;cAmFf,8BACX,SAAS,YACT,qBACC;;;;;;iBAwBa,oBACd,MAAM,6BACL"}
1
+ {"version":3,"file":"createOAuthProvider.d.ts","names":[],"sources":["../../src/auth/createOAuthProvider.ts"],"mappings":";;;;iBAsCgB,wBAAwB;KAgB5B;EACV;EACA;;EAEA,QAAQ,QAAQ;IAAiB;;EACjC,SAAS;EACT;;EAEA,qBAAqB,KAAK;;KAcvB,cAAc,QAAQ;EAAiB;;KAEvC;EACH,SAAS;EACT;EACA,oBAAoB;EACpB;;cAUW,uBACX,OAAO,yCACP,QAAQ;;;;;;cAkHG,8BACX,SAAS,YACT,qBACC;;;;;;iBA2Ba,oBACd,MAAM,6BACL"}
@@ -1,3 +1,4 @@
1
+ import { isAuthStateForServerUrl, normalizeMcpServerUrl } from "../utils/serverUrl.js";
1
2
  //#region src/auth/createOAuthProvider.ts
2
3
  const STATE_PREFIX = "aui-mcp:";
3
4
  function bytesToBase64Url(bytes) {
@@ -26,6 +27,15 @@ function decodeServerIdFromState(state) {
26
27
  return null;
27
28
  }
28
29
  }
30
+ const registeredClientId = (state) => state?.clientInformationSource === "registered" ? state.clientInformation?.client_id : void 0;
31
+ const hasUsableOAuthTokens = (state, config) => {
32
+ const clientId = config.clientId ?? registeredClientId(state);
33
+ return clientId !== void 0 && state?.tokens !== void 0 && state.tokensClientId === clientId;
34
+ };
35
+ const hasUsableRegisteredClientInformation = (state, config) => {
36
+ const clientId = registeredClientId(state);
37
+ return clientId !== void 0 && (config.clientId === void 0 || config.clientId === clientId);
38
+ };
29
39
  const anchorByStorage = /* @__PURE__ */ new WeakMap();
30
40
  const anchorByScope = /* @__PURE__ */ new Map();
31
41
  const anchorRegistry = new FinalizationRegistry((scopeId) => {
@@ -46,7 +56,7 @@ const getStorageIdentity = (storage) => {
46
56
  return anchor;
47
57
  };
48
58
  const persistenceByIdentity = /* @__PURE__ */ new WeakMap();
49
- const getPersistence = (storage, serverId) => {
59
+ const getPersistence = (storage, serverId, serverUrl) => {
50
60
  const identity = getStorageIdentity(storage);
51
61
  let byServerId = persistenceByIdentity.get(identity);
52
62
  if (!byServerId) {
@@ -56,14 +66,27 @@ const getPersistence = (storage, serverId) => {
56
66
  let persistence = byServerId.get(serverId);
57
67
  if (!persistence) {
58
68
  persistence = {
59
- cached: null,
60
- cachePromise: null,
69
+ endpoint: null,
61
70
  queue: Promise.resolve(),
62
71
  invalidated: false
63
72
  };
64
73
  byServerId.set(serverId, persistence);
65
74
  }
66
- return persistence;
75
+ let endpoint = persistence.endpoint;
76
+ if (endpoint?.serverUrl !== serverUrl) {
77
+ if (endpoint) endpoint.invalidated = true;
78
+ endpoint = {
79
+ serverUrl,
80
+ cached: null,
81
+ cachePromise: null,
82
+ invalidated: false
83
+ };
84
+ persistence.endpoint = endpoint;
85
+ }
86
+ return {
87
+ persistence,
88
+ endpoint
89
+ };
67
90
  };
68
91
  /**
69
92
  * Clears persisted OAuth state after the in-flight load and every queued write
@@ -81,7 +104,10 @@ const clearOAuthProviderAuthState = async (storage, serverId) => {
81
104
  persistence.invalidated = true;
82
105
  byServerId.delete(serverId);
83
106
  if (byServerId.size === 0) persistenceByIdentity.delete(identity);
84
- await Promise.allSettled([persistence.cachePromise, persistence.queue]);
107
+ if (persistence.endpoint) persistence.endpoint.invalidated = true;
108
+ const cachePromise = persistence.endpoint?.cachePromise;
109
+ if (cachePromise) await Promise.allSettled([cachePromise]);
110
+ await persistence.queue;
85
111
  await storage.clearAuthState(serverId);
86
112
  };
87
113
  /**
@@ -90,10 +116,11 @@ const clearOAuthProviderAuthState = async (storage, serverId) => {
90
116
  * load/save and the redirect step.
91
117
  */
92
118
  function createOAuthProvider(opts) {
93
- const { serverId, config, storage, redirectUri, onAuthorizationUrl } = opts;
94
- const persistence = getPersistence(storage, serverId);
119
+ const { serverId, serverUrl, config, storage, redirectUri, onAuthorizationUrl } = opts;
120
+ const normalizedServerUrl = normalizeMcpServerUrl(serverUrl);
121
+ const { persistence, endpoint } = getPersistence(storage, serverId, normalizedServerUrl);
95
122
  let pendingState;
96
- const staticClientInformation = (() => {
123
+ const configuredClientInformation = () => {
97
124
  if (!config.clientId) return void 0;
98
125
  const ci = {
99
126
  client_id: config.clientId,
@@ -101,41 +128,64 @@ function createOAuthProvider(opts) {
101
128
  };
102
129
  if (config.clientSecret) ci.client_secret = config.clientSecret;
103
130
  return ci;
104
- })();
131
+ };
132
+ let clientInformationOverlay = configuredClientInformation();
133
+ const activeClientId = (cache) => clientInformationOverlay?.client_id ?? registeredClientId(cache);
105
134
  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) => {
135
+ if (endpoint.invalidated) return Promise.resolve({});
136
+ if (endpoint.cached) return Promise.resolve(endpoint.cached);
137
+ if (endpoint.cachePromise) return endpoint.cachePromise;
138
+ endpoint.cachePromise = persistence.queue.then(() => storage.loadAuthState(serverId)).then(async (persisted) => {
109
139
  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;
140
+ let needsMigration = false;
141
+ if (endpoint.invalidated) return initial;
142
+ if (persisted && isAuthStateForServerUrl(persisted, normalizedServerUrl)) {
143
+ if (hasUsableRegisteredClientInformation(persisted, config) && persisted.clientInformation) {
144
+ initial.clientInformation = persisted.clientInformation;
145
+ initial.clientInformationSource = "registered";
146
+ } else if (persisted?.clientInformation || persisted?.clientInformationSource !== void 0) needsMigration = true;
147
+ if (hasUsableOAuthTokens(persisted, config)) {
148
+ initial.tokens = persisted.tokens;
149
+ initial.tokensClientId = persisted.tokensClientId;
150
+ } else if (persisted?.tokens || persisted?.tokensClientId !== void 0) needsMigration = true;
151
+ if (persisted?.token) initial.token = persisted.token;
152
+ if (persisted?.codeVerifier) initial.codeVerifier = persisted.codeVerifier;
153
+ if (persisted?.state) initial.state = persisted.state;
154
+ if (persisted?.discoveryState) initial.discoveryState = persisted.discoveryState;
155
+ }
156
+ endpoint.cached = initial;
157
+ if (needsMigration) await persist().catch(() => {});
116
158
  return initial;
117
159
  }, (error) => {
118
- persistence.cachePromise = null;
160
+ endpoint.cachePromise = null;
119
161
  throw error;
120
162
  });
121
- return persistence.cachePromise;
163
+ return endpoint.cachePromise;
122
164
  };
123
- const persist = () => {
165
+ function persist() {
124
166
  const task = persistence.queue.then(async () => {
125
- if (persistence.invalidated) return;
126
- const c = persistence.cached;
167
+ if (persistence.invalidated || endpoint.invalidated) return;
168
+ const c = endpoint.cached;
127
169
  if (!c) return;
128
170
  const next = {};
129
- if (c.tokens) next.tokens = c.tokens;
130
- if (c.clientInformation) next.clientInformation = c.clientInformation;
171
+ if (hasUsableOAuthTokens(c, config) && c.tokens && c.tokensClientId) {
172
+ next.tokens = c.tokens;
173
+ next.tokensClientId = c.tokensClientId;
174
+ }
175
+ if (c.clientInformation && c.clientInformationSource === "registered") {
176
+ next.clientInformation = c.clientInformation;
177
+ next.clientInformationSource = "registered";
178
+ }
179
+ if (c.token) next.token = c.token;
131
180
  if (c.codeVerifier) next.codeVerifier = c.codeVerifier;
132
181
  if (c.state) next.state = c.state;
133
182
  if (c.discoveryState) next.discoveryState = c.discoveryState;
183
+ next.serverUrl = normalizedServerUrl;
134
184
  await storage.saveAuthState(serverId, next);
135
185
  });
136
186
  persistence.queue = task.catch(() => {});
137
187
  return task;
138
- };
188
+ }
139
189
  const clientMetadata = {
140
190
  client_name: "assistant-ui",
141
191
  redirect_uris: [redirectUri],
@@ -158,19 +208,36 @@ function createOAuthProvider(opts) {
158
208
  },
159
209
  async clientInformation() {
160
210
  const c = await loadCache();
161
- return staticClientInformation ?? c.clientInformation;
211
+ if (clientInformationOverlay) return clientInformationOverlay;
212
+ if (c.clientInformationSource !== "registered") return void 0;
213
+ return c.clientInformation;
162
214
  },
163
215
  async saveClientInformation(info) {
216
+ if (clientInformationOverlay) {
217
+ clientInformationOverlay = info;
218
+ return;
219
+ }
164
220
  const c = await loadCache();
165
221
  c.clientInformation = info;
222
+ c.clientInformationSource = "registered";
223
+ if (c.tokensClientId !== c.clientInformation.client_id) {
224
+ delete c.tokens;
225
+ delete c.tokensClientId;
226
+ }
166
227
  await persist();
167
228
  },
168
229
  async tokens() {
169
- return (await loadCache()).tokens;
230
+ const c = await loadCache();
231
+ const clientId = activeClientId(c);
232
+ if (clientId === void 0 || c.tokensClientId !== clientId) return void 0;
233
+ return c.tokens;
170
234
  },
171
235
  async saveTokens(tokens) {
172
236
  const c = await loadCache();
173
237
  c.tokens = tokens;
238
+ const clientId = activeClientId(c);
239
+ if (clientId) c.tokensClientId = clientId;
240
+ else delete c.tokensClientId;
174
241
  delete c.state;
175
242
  await persist();
176
243
  },
@@ -201,8 +268,19 @@ function createOAuthProvider(opts) {
201
268
  },
202
269
  async invalidateCredentials(scope) {
203
270
  const c = await loadCache();
204
- if (scope === "all" || scope === "tokens") delete c.tokens;
205
- if (scope === "all" || scope === "client") delete c.clientInformation;
271
+ if (scope === "all" || scope === "tokens") {
272
+ delete c.tokens;
273
+ delete c.tokensClientId;
274
+ }
275
+ if (scope === "all" || scope === "client") {
276
+ delete c.clientInformation;
277
+ delete c.clientInformationSource;
278
+ if (!config.clientId) {
279
+ delete c.tokens;
280
+ delete c.tokensClientId;
281
+ }
282
+ clientInformationOverlay = configuredClientInformation();
283
+ }
206
284
  if (scope === "all" || scope === "verifier") {
207
285
  delete c.codeVerifier;
208
286
  delete c.state;
@@ -213,6 +291,6 @@ function createOAuthProvider(opts) {
213
291
  };
214
292
  }
215
293
  //#endregion
216
- export { clearOAuthProviderAuthState, createOAuthProvider, decodeServerIdFromState };
294
+ export { clearOAuthProviderAuthState, createOAuthProvider, decodeServerIdFromState, hasUsableOAuthTokens };
217
295
 
218
296
  //# 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","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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"}
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,12 +1,16 @@
1
1
  import { OAuthClientInformationFull, OAuthDiscoveryState, OAuthTokens } from "@modelcontextprotocol/client";
2
2
  //#region src/auth/types.d.ts
3
3
  type MCPPersistedAuthState = {
4
+ /** MCP server URL this authentication state belongs to. Required with credentials. */
5
+ serverUrl?: string;
4
6
  tokens?: OAuthTokens;
7
+ tokensClientId?: string;
5
8
  clientInformation?: OAuthClientInformationFull;
9
+ clientInformationSource?: "registered";
6
10
  codeVerifier?: string;
7
11
  state?: string;
8
12
  discoveryState?: OAuthDiscoveryState;
9
- /** Bearer token (entered at add-form time). */
13
+ /** Host-persisted bearer token. Must be paired with serverUrl. */
10
14
  token?: string;
11
15
  };
12
16
  //#endregion
@@ -1 +1 @@
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
+ {"version":3,"file":"types.d.ts","names":[],"sources":["../../src/auth/types.ts"],"mappings":";;KAMY;;EAEV;EACA,SAAS;EACT;EACA,oBAAoB;EACpB;EACA;EACA;EACA,iBAAiB;;EAEjB"}
@@ -1,11 +1,11 @@
1
1
  import { useAddForm } from "./context.js";
2
2
  import { c } from "@assistant-ui/tap/react-shim/compiler-runtime";
3
- import { jsx } from "react/jsx-runtime";
3
+ import { jsx, jsxs } from "react/jsx-runtime";
4
4
  //#region src/primitives/addForm/McpAddFormAuthFields.tsx
5
5
  const McpAddFormPrimitiveAuthFields = (t0) => {
6
- const $ = c(13);
6
+ const $ = c(27);
7
7
  const { children } = t0;
8
- const { state, setField } = useAddForm();
8
+ const { state, ids, setField } = useAddForm();
9
9
  if (children) {
10
10
  const Render = children;
11
11
  let t1;
@@ -19,47 +19,90 @@ const McpAddFormPrimitiveAuthFields = (t0) => {
19
19
  }
20
20
  if (state.authType === "bearer") {
21
21
  let t1;
22
- if ($[3] !== setField) {
23
- t1 = (e) => setField("bearerToken", e.target.value);
24
- $[3] = setField;
22
+ if ($[3] !== ids.bearerToken) {
23
+ t1 = /* @__PURE__ */ jsx("label", {
24
+ htmlFor: ids.bearerToken,
25
+ "data-mcp-auth-field-label": "bearer-token",
26
+ children: "Bearer token"
27
+ });
28
+ $[3] = ids.bearerToken;
25
29
  $[4] = t1;
26
30
  } else t1 = $[4];
27
31
  let t2;
28
- if ($[5] !== state.bearerToken || $[6] !== t1) {
29
- t2 = /* @__PURE__ */ jsx("input", {
32
+ if ($[5] !== setField) {
33
+ t2 = (e) => setField("bearerToken", e.target.value);
34
+ $[5] = setField;
35
+ $[6] = t2;
36
+ } else t2 = $[6];
37
+ const t3 = state.errorField === "bearerToken" ? true : void 0;
38
+ const t4 = state.errorField === "bearerToken" ? ids.error : void 0;
39
+ let t5;
40
+ if ($[7] !== ids.bearerToken || $[8] !== state.bearerToken || $[9] !== t2 || $[10] !== t3 || $[11] !== t4) {
41
+ t5 = /* @__PURE__ */ jsx("input", {
42
+ id: ids.bearerToken,
30
43
  type: "password",
31
- placeholder: "Bearer token",
32
44
  value: state.bearerToken,
33
- onChange: t1,
45
+ onChange: t2,
46
+ "aria-invalid": t3,
47
+ "aria-describedby": t4,
34
48
  "data-mcp-auth-field": "bearer-token"
35
49
  });
36
- $[5] = state.bearerToken;
37
- $[6] = t1;
38
- $[7] = t2;
39
- } else t2 = $[7];
40
- return t2;
50
+ $[7] = ids.bearerToken;
51
+ $[8] = state.bearerToken;
52
+ $[9] = t2;
53
+ $[10] = t3;
54
+ $[11] = t4;
55
+ $[12] = t5;
56
+ } else t5 = $[12];
57
+ let t6;
58
+ if ($[13] !== t1 || $[14] !== t5) {
59
+ t6 = /* @__PURE__ */ jsxs("div", { children: [t1, t5] });
60
+ $[13] = t1;
61
+ $[14] = t5;
62
+ $[15] = t6;
63
+ } else t6 = $[15];
64
+ return t6;
41
65
  }
42
66
  if (state.authType === "oauth") {
43
67
  let t1;
44
- if ($[8] !== setField) {
45
- t1 = (e_0) => setField("scopes", e_0.target.value);
46
- $[8] = setField;
47
- $[9] = t1;
48
- } else t1 = $[9];
68
+ if ($[16] !== ids.scopes) {
69
+ t1 = /* @__PURE__ */ jsx("label", {
70
+ htmlFor: ids.scopes,
71
+ "data-mcp-auth-field-label": "oauth-scopes",
72
+ children: "OAuth scopes"
73
+ });
74
+ $[16] = ids.scopes;
75
+ $[17] = t1;
76
+ } else t1 = $[17];
49
77
  let t2;
50
- if ($[10] !== state.scopes || $[11] !== t1) {
51
- t2 = /* @__PURE__ */ jsx("input", {
78
+ if ($[18] !== setField) {
79
+ t2 = (e_0) => setField("scopes", e_0.target.value);
80
+ $[18] = setField;
81
+ $[19] = t2;
82
+ } else t2 = $[19];
83
+ let t3;
84
+ if ($[20] !== ids.scopes || $[21] !== state.scopes || $[22] !== t2) {
85
+ t3 = /* @__PURE__ */ jsx("input", {
86
+ id: ids.scopes,
52
87
  type: "text",
53
88
  placeholder: "Scopes (space-separated, optional)",
54
89
  value: state.scopes,
55
- onChange: t1,
90
+ onChange: t2,
56
91
  "data-mcp-auth-field": "oauth-scopes"
57
92
  });
58
- $[10] = state.scopes;
59
- $[11] = t1;
60
- $[12] = t2;
61
- } else t2 = $[12];
62
- return t2;
93
+ $[20] = ids.scopes;
94
+ $[21] = state.scopes;
95
+ $[22] = t2;
96
+ $[23] = t3;
97
+ } else t3 = $[23];
98
+ let t4;
99
+ if ($[24] !== t1 || $[25] !== t3) {
100
+ t4 = /* @__PURE__ */ jsxs("div", { children: [t1, t3] });
101
+ $[24] = t1;
102
+ $[25] = t3;
103
+ $[26] = t4;
104
+ } else t4 = $[26];
105
+ return t4;
63
106
  }
64
107
  return null;
65
108
  };
@@ -1 +1 @@
1
- {"version":3,"file":"McpAddFormAuthFields.js","names":["FC","AddFormAuthType","useAddForm","McpAddFormPrimitiveAuthFields","Props","children","authType","t0","$","_c","state","setField","Render","t1","e","target","value","t2","bearerToken","e_0","scopes","displayName"],"sources":["../../../src/primitives/addForm/McpAddFormAuthFields.tsx"],"sourcesContent":["import type { FC } from \"react\";\nimport { type AddFormAuthType, useAddForm } from \"./context\";\n\nexport namespace McpAddFormPrimitiveAuthFields {\n export type Props = {\n /**\n * Optional render override. Receives the current auth type so apps can render\n * fully custom inputs. Defaults to a minimal built-in for bearer / oauth.\n */\n children?: FC<{ authType: AddFormAuthType }>;\n };\n}\n\nexport const McpAddFormPrimitiveAuthFields: FC<\n McpAddFormPrimitiveAuthFields.Props\n> = ({ children }) => {\n const { state, setField } = useAddForm();\n\n if (children) {\n const Render = children;\n return <Render authType={state.authType} />;\n }\n\n if (state.authType === \"bearer\") {\n return (\n <input\n type=\"password\"\n placeholder=\"Bearer token\"\n value={state.bearerToken}\n onChange={(e) => setField(\"bearerToken\", e.target.value)}\n data-mcp-auth-field=\"bearer-token\"\n />\n );\n }\n\n if (state.authType === \"oauth\") {\n return (\n <input\n type=\"text\"\n placeholder=\"Scopes (space-separated, optional)\"\n value={state.scopes}\n onChange={(e) => setField(\"scopes\", e.target.value)}\n data-mcp-auth-field=\"oauth-scopes\"\n />\n );\n }\n\n return null;\n};\n\nMcpAddFormPrimitiveAuthFields.displayName = \"McpAddFormPrimitive.AuthFields\";\n"],"mappings":";;;;AAaA,MAAaG,iCAETI,OAAA;CAAA,MAAAC,IAAAC,EAAA,EAAA;CAAC,MAAA,EAAAJ,aAAAE;CACH,MAAA,EAAAG,OAAAC,aAA4BT,WAAW;CAEvC,IAAIG,UAAQ;EACV,MAAAO,SAAeP;EAAS,IAAAQ;EAAA,IAAAL,EAAA,OAAAI,UAAAJ,EAAA,OAAAE,MAAAJ,UAAA;GACjBO,KAAA,oBAAC,QAAD,EAAkB,UAAAH,MAAKJ,SAAS,CAAA;GAAIE,EAAA,KAAAI;GAAAJ,EAAA,KAAAE,MAAAJ;GAAAE,EAAA,KAAAK;EAAA,OAAAA,KAAAL,EAAA;EAAA,OAApCK;CAAoC;CAG7C,IAAIH,MAAKJ,aAAc,UAAQ;EAAA,IAAAO;EAAA,IAAAL,EAAA,OAAAG,UAAA;GAMfE,MAAAC,MAAOH,SAAS,eAAeG,EAACC,OAAOC,KAAM;GAACR,EAAA,KAAAG;GAAAH,EAAA,KAAAK;EAAA,OAAAA,KAAAL,EAAA;EAAA,IAAAS;EAAA,IAAAT,EAAA,OAAAE,MAAAQ,eAAAV,EAAA,OAAAK,IAAA;GAJ1DI,KAAA,oBAAA,SAAA;IACO,MAAA;IACO,aAAA;IACL,OAAAP,MAAKQ;IACF,UAAAL;IACU,uBAAA;GAAc,CAAA;GAClCL,EAAA,KAAAE,MAAAQ;GAAAV,EAAA,KAAAK;GAAAL,EAAA,KAAAS;EAAA,OAAAA,KAAAT,EAAA;EAAA,OANFS;CAME;CAIN,IAAIP,MAAKJ,aAAc,SAAO;EAAA,IAAAO;EAAA,IAAAL,EAAA,OAAAG,UAAA;GAMdE,MAAAM,QAAOR,SAAS,UAAUG,IAACC,OAAOC,KAAM;GAACR,EAAA,KAAAG;GAAAH,EAAA,KAAAK;EAAA,OAAAA,KAAAL,EAAA;EAAA,IAAAS;EAAA,IAAAT,EAAA,QAAAE,MAAAU,UAAAZ,EAAA,QAAAK,IAAA;GAJrDI,KAAA,oBAAA,SAAA;IACO,MAAA;IACO,aAAA;IACL,OAAAP,MAAKU;IACF,UAAAP;IACU,uBAAA;GAAc,CAAA;GAClCL,EAAA,MAAAE,MAAAU;GAAAZ,EAAA,MAAAK;GAAAL,EAAA,MAAAS;EAAA,OAAAA,KAAAT,EAAA;EAAA,OANFS;CAME;CAEL,OAEM;AAAI;AAGbd,8BAA8BkB,cAAc"}
1
+ {"version":3,"file":"McpAddFormAuthFields.js","names":["FC","AddFormAuthType","useAddForm","McpAddFormPrimitiveAuthFields","Props","children","authType","t0","$","_c","state","ids","setField","Render","t1","bearerToken","t2","e","target","value","t3","errorField","undefined","t4","error","t5","t6","scopes","e_0","displayName"],"sources":["../../../src/primitives/addForm/McpAddFormAuthFields.tsx"],"sourcesContent":["import type { FC } from \"react\";\nimport { type AddFormAuthType, useAddForm } from \"./context\";\n\nexport namespace McpAddFormPrimitiveAuthFields {\n export type Props = {\n /**\n * Optional render override. Receives the current auth type so apps can render\n * fully custom inputs. Defaults to a minimal built-in for bearer / oauth.\n */\n children?: FC<{ authType: AddFormAuthType }>;\n };\n}\n\nexport const McpAddFormPrimitiveAuthFields: FC<\n McpAddFormPrimitiveAuthFields.Props\n> = ({ children }) => {\n const { state, ids, setField } = useAddForm();\n\n if (children) {\n const Render = children;\n return <Render authType={state.authType} />;\n }\n\n if (state.authType === \"bearer\") {\n return (\n <div>\n <label\n htmlFor={ids.bearerToken}\n data-mcp-auth-field-label=\"bearer-token\"\n >\n Bearer token\n </label>\n <input\n id={ids.bearerToken}\n type=\"password\"\n value={state.bearerToken}\n onChange={(e) => setField(\"bearerToken\", e.target.value)}\n aria-invalid={state.errorField === \"bearerToken\" ? true : undefined}\n aria-describedby={\n state.errorField === \"bearerToken\" ? ids.error : undefined\n }\n data-mcp-auth-field=\"bearer-token\"\n />\n </div>\n );\n }\n\n if (state.authType === \"oauth\") {\n return (\n <div>\n <label htmlFor={ids.scopes} data-mcp-auth-field-label=\"oauth-scopes\">\n OAuth scopes\n </label>\n <input\n id={ids.scopes}\n type=\"text\"\n placeholder=\"Scopes (space-separated, optional)\"\n value={state.scopes}\n onChange={(e) => setField(\"scopes\", e.target.value)}\n data-mcp-auth-field=\"oauth-scopes\"\n />\n </div>\n );\n }\n\n return null;\n};\n\nMcpAddFormPrimitiveAuthFields.displayName = \"McpAddFormPrimitive.AuthFields\";\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"McpAddFormError.d.ts","names":[],"sources":["../../../src/primitives/addForm/McpAddFormError.tsx"],"mappings":";;;kBAQiB;OACH,UAAU,oBAAoB,UAAU;OACxC,QAAQ,gCAAgC,UAAU;;cAGnD,0CAAwB,0BAAA,qBAAA,gBAAA,kCAAA,eAAA;;4BAWnC,cAAA"}
1
+ {"version":3,"file":"McpAddFormError.d.ts","names":[],"sources":["../../../src/primitives/addForm/McpAddFormError.tsx"],"mappings":";;;kBASiB;OACH,UAAU,oBAAoB,UAAU;OACxC,QAAQ,gCAAgC,UAAU;;cAGnD,0CAAwB,0BAAA,qBAAA,gBAAA,kCAAA,eAAA;;4BAwBnC,cAAA"}
@@ -1,27 +1,47 @@
1
1
  import { useAddForm } from "./context.js";
2
2
  import { c } from "@assistant-ui/tap/react-shim/compiler-runtime";
3
- import { forwardRef } from "@assistant-ui/tap/react-shim";
3
+ import { forwardRef, isValidElement } from "@assistant-ui/tap/react-shim";
4
4
  import { Primitive } from "@radix-ui/react-primitive";
5
5
  import { jsx } from "react/jsx-runtime";
6
6
  //#region src/primitives/addForm/McpAddFormError.tsx
7
7
  const McpAddFormPrimitiveError = forwardRef((props, ref) => {
8
- const $ = c(4);
9
- const { state } = useAddForm();
8
+ const $ = c(10);
9
+ const { state, ids } = useAddForm();
10
10
  if (!state.error) return null;
11
- const t0 = props.children ?? state.error;
12
- let t1;
13
- if ($[0] !== props || $[1] !== ref || $[2] !== t0) {
14
- t1 = /* @__PURE__ */ jsx(Primitive.div, {
11
+ const customId = (props.asChild && isValidElement(props.children) ? props.children.props.id : void 0) ?? props.id;
12
+ const needsDescriptionWrapper = customId !== void 0 && customId !== ids.error;
13
+ const t0 = needsDescriptionWrapper ? props.id : ids.error;
14
+ const t1 = props.role ?? "alert";
15
+ const t2 = props.children ?? state.error;
16
+ let t3;
17
+ if ($[0] !== props || $[1] !== ref || $[2] !== t0 || $[3] !== t1 || $[4] !== t2) {
18
+ t3 = /* @__PURE__ */ jsx(Primitive.div, {
15
19
  ...props,
20
+ id: t0,
21
+ role: t1,
16
22
  ref,
17
- children: t0
23
+ children: t2
18
24
  });
19
25
  $[0] = props;
20
26
  $[1] = ref;
21
27
  $[2] = t0;
22
28
  $[3] = t1;
23
- } else t1 = $[3];
24
- return t1;
29
+ $[4] = t2;
30
+ $[5] = t3;
31
+ } else t3 = $[5];
32
+ const error = t3;
33
+ let t4;
34
+ if ($[6] !== error || $[7] !== ids || $[8] !== needsDescriptionWrapper) {
35
+ t4 = needsDescriptionWrapper ? /* @__PURE__ */ jsx("div", {
36
+ id: ids.error,
37
+ children: error
38
+ }) : error;
39
+ $[6] = error;
40
+ $[7] = ids;
41
+ $[8] = needsDescriptionWrapper;
42
+ $[9] = t4;
43
+ } else t4 = $[9];
44
+ return t4;
25
45
  });
26
46
  McpAddFormPrimitiveError.displayName = "McpAddFormPrimitive.Error";
27
47
  //#endregion