@assistant-ui/react-mcp 0.1.12 → 0.1.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/dist/auth/createOAuthProvider.d.ts.map +1 -1
  2. package/dist/auth/createOAuthProvider.js +11 -0
  3. package/dist/auth/createOAuthProvider.js.map +1 -1
  4. package/dist/auth/types.d.ts +2 -1
  5. package/dist/auth/types.d.ts.map +1 -1
  6. package/dist/hooks/useMcpOAuthCallback.d.ts.map +1 -1
  7. package/dist/hooks/useMcpOAuthCallback.js +3 -16
  8. package/dist/hooks/useMcpOAuthCallback.js.map +1 -1
  9. package/dist/primitives/addForm/McpAddFormRoot.d.ts.map +1 -1
  10. package/dist/primitives/addForm/McpAddFormRoot.js +2 -1
  11. package/dist/primitives/addForm/McpAddFormRoot.js.map +1 -1
  12. package/dist/resources/McpManagerResource.d.ts.map +1 -1
  13. package/dist/resources/McpManagerResource.js +47 -46
  14. package/dist/resources/McpManagerResource.js.map +1 -1
  15. package/dist/resources/McpServerResource.d.ts.map +1 -1
  16. package/dist/resources/McpServerResource.js +13 -3
  17. package/dist/resources/McpServerResource.js.map +1 -1
  18. package/dist/resources/storage/McpLocalStorage.d.ts.map +1 -1
  19. package/dist/resources/storage/McpLocalStorage.js +22 -1
  20. package/dist/resources/storage/McpLocalStorage.js.map +1 -1
  21. package/dist/utils/invokeMcpCallback.d.ts +5 -0
  22. package/dist/utils/invokeMcpCallback.d.ts.map +1 -0
  23. package/dist/utils/invokeMcpCallback.js +19 -0
  24. package/dist/utils/invokeMcpCallback.js.map +1 -0
  25. package/package.json +6 -6
  26. package/src/auth/createOAuthProvider.test.ts +86 -0
  27. package/src/auth/createOAuthProvider.ts +15 -0
  28. package/src/auth/types.ts +2 -0
  29. package/src/hooks/useMcpOAuthCallback.tsx +3 -36
  30. package/src/primitives/addForm/McpAddFormRoot.test.tsx +80 -0
  31. package/src/primitives/addForm/McpAddFormRoot.tsx +2 -1
  32. package/src/resources/McpManagerResource.test.ts +21 -0
  33. package/src/resources/McpManagerResource.ts +12 -7
  34. package/src/resources/McpServerResource.test.ts +141 -1
  35. package/src/resources/McpServerResource.ts +14 -2
  36. package/src/resources/storage/McpLocalStorage.test.ts +180 -0
  37. package/src/resources/storage/McpLocalStorage.ts +53 -0
  38. package/src/utils/invokeMcpCallback.ts +27 -0
@@ -1 +1 @@
1
- {"version":3,"file":"createOAuthProvider.d.ts","names":[],"sources":["../../src/auth/createOAuthProvider.ts"],"mappings":";;;;iBAgCgB,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;;;;;;;iBAQZ,oBACd,MAAM,6BACL"}
@@ -48,6 +48,7 @@ function createOAuthProvider(opts) {
48
48
  initial.clientInformation = ci;
49
49
  } else if (persisted?.clientInformation) initial.clientInformation = persisted.clientInformation;
50
50
  if (persisted?.codeVerifier) initial.codeVerifier = persisted.codeVerifier;
51
+ if (persisted?.discoveryState) initial.discoveryState = persisted.discoveryState;
51
52
  cached = initial;
52
53
  return cached;
53
54
  };
@@ -58,6 +59,7 @@ function createOAuthProvider(opts) {
58
59
  if (c.tokens) next.tokens = c.tokens;
59
60
  if (c.clientInformation) next.clientInformation = c.clientInformation;
60
61
  if (c.codeVerifier) next.codeVerifier = c.codeVerifier;
62
+ if (c.discoveryState) next.discoveryState = c.discoveryState;
61
63
  await storage.saveAuthState(serverId, next);
62
64
  };
63
65
  const clientMetadata = {
@@ -108,11 +110,20 @@ function createOAuthProvider(opts) {
108
110
  if (!c.codeVerifier) throw new Error("No code verifier saved for this OAuth flow");
109
111
  return c.codeVerifier;
110
112
  },
113
+ async saveDiscoveryState(discoveryState) {
114
+ const c = await loadCache();
115
+ c.discoveryState = discoveryState;
116
+ await persist();
117
+ },
118
+ async discoveryState() {
119
+ return (await loadCache()).discoveryState;
120
+ },
111
121
  async invalidateCredentials(scope) {
112
122
  const c = await loadCache();
113
123
  if (scope === "all" || scope === "tokens") delete c.tokens;
114
124
  if (scope === "all" || scope === "client") delete c.clientInformation;
115
125
  if (scope === "all" || scope === "verifier") delete c.codeVerifier;
126
+ if (scope === "all" || scope === "discovery") delete c.discoveryState;
116
127
  await persist();
117
128
  }
118
129
  };
@@ -1 +1 @@
1
- {"version":3,"file":"createOAuthProvider.js","names":["OAuthClientProvider","OAuthClientInformationFull","OAuthClientMetadata","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","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","invalidateCredentials"],"sources":["../../src/auth/createOAuthProvider.ts"],"sourcesContent":["import type {\n OAuthClientProvider,\n OAuthClientInformationFull,\n OAuthClientMetadata,\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 };\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 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 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 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 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","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,9 +1,10 @@
1
- import { OAuthClientInformationFull, OAuthTokens } from "@modelcontextprotocol/client";
1
+ import { OAuthClientInformationFull, OAuthDiscoveryState, OAuthTokens } from "@modelcontextprotocol/client";
2
2
  //#region src/auth/types.d.ts
3
3
  type MCPPersistedAuthState = {
4
4
  tokens?: OAuthTokens;
5
5
  clientInformation?: OAuthClientInformationFull;
6
6
  codeVerifier?: string;
7
+ discoveryState?: OAuthDiscoveryState;
7
8
  /** Bearer token (entered at add-form time). */
8
9
  token?: string;
9
10
  };
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","names":[],"sources":["../../src/auth/types.ts"],"mappings":";;KAKY;EACV,SAAS;EACT,oBAAoB;EACpB;;EAEA"}
1
+ {"version":3,"file":"types.d.ts","names":[],"sources":["../../src/auth/types.ts"],"mappings":";;KAMY;EACV,SAAS;EACT,oBAAoB;EACpB;EACA,iBAAiB;;EAEjB"}
@@ -1 +1 @@
1
- {"version":3,"file":"useMcpOAuthCallback.d.ts","names":[],"sources":["../../src/hooks/useMcpOAuthCallback.tsx"],"mappings":";;cAkCa,8BACX,cACA,4BACC;KAWS;;EAEV;EACA,cAAc;EACd,WAAW,KAAK;;KAGN;EACV;EACA;EACA,OAAO;;iBAGO,oBACd,OAAM,6BACL;cA0DU,kBAAkB,GAC7B;EACE,YAAY,QAAQ,8BAA8B"}
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,23 +1,10 @@
1
1
  import { decodeServerIdFromState } from "../auth/createOAuthProvider.js";
2
+ import { invokeMcpCallback } from "../utils/invokeMcpCallback.js";
2
3
  import { useAui } from "@assistant-ui/store";
3
4
  import { c } from "@assistant-ui/tap/react-shim/compiler-runtime";
4
5
  import { useEffect, useRef, useState } from "@assistant-ui/tap/react-shim";
5
6
  import { Fragment, jsx } from "react/jsx-runtime";
6
7
  //#region src/hooks/useMcpOAuthCallback.tsx
7
- const reportCallbackError = (name, error) => {
8
- console.error(`[react-mcp] ${name} callback threw an error`, error);
9
- };
10
- const invokeMcpOAuthCallback = (name, callback, ...args) => {
11
- if (!callback) return;
12
- try {
13
- const result = callback(...args);
14
- if (result !== null && (typeof result === "object" || typeof result === "function") && "then" in result && typeof result.then === "function") Promise.resolve(result).catch((error) => {
15
- reportCallbackError(name, error);
16
- });
17
- } catch (error) {
18
- reportCallbackError(name, error);
19
- }
20
- };
21
8
  const createMcpOAuthCallbackError = (err, serverId) => {
22
9
  const message = err instanceof Error ? err.message : String(err);
23
10
  if (serverId) return new Error(`MCP OAuth callback for server "${serverId}" failed: ${message}`, { cause: err });
@@ -66,10 +53,10 @@ function useMcpOAuthCallback(opts = {}) {
66
53
  serverId,
67
54
  error
68
55
  });
69
- invokeMcpOAuthCallback("onError", optsRef.current.onError, error);
56
+ invokeMcpCallback("onError", optsRef.current.onError, error);
70
57
  return;
71
58
  }
72
- invokeMcpOAuthCallback("onComplete", optsRef.current.onComplete, serverId);
59
+ invokeMcpCallback("onComplete", optsRef.current.onComplete, serverId);
73
60
  })();
74
61
  }, [aui, opts.url]);
75
62
  return result;
@@ -1 +1 @@
1
- {"version":3,"file":"useMcpOAuthCallback.js","names":["FC","ReactNode","useEffect","useRef","useState","useAui","decodeServerIdFromState","McpOAuthCallbackName","reportCallbackError","name","error","console","invokeMcpOAuthCallback","callback","args","TArgs","result","then","Promise","resolve","catch","createMcpOAuthCallbackError","err","serverId","Error","message","String","cause","UseMcpOAuthCallbackOptions","url","onComplete","onError","UseMcpOAuthCallbackResult","status","useMcpOAuthCallback","opts","aui","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\";\n\ntype McpOAuthCallbackName = \"onComplete\" | \"onError\";\n\nconst reportCallbackError = (name: McpOAuthCallbackName, error: unknown) => {\n console.error(`[react-mcp] ${name} callback threw an error`, error);\n};\n\nconst invokeMcpOAuthCallback = <TArgs extends unknown[]>(\n name: McpOAuthCallbackName,\n callback: ((...args: TArgs) => void) | undefined,\n ...args: TArgs\n) => {\n if (!callback) return;\n\n try {\n const result = callback(...args) as unknown;\n if (\n result !== null &&\n (typeof result === \"object\" || typeof result === \"function\") &&\n \"then\" in result &&\n typeof result.then === \"function\"\n ) {\n void Promise.resolve(result).catch((error) => {\n reportCallbackError(name, error);\n });\n }\n } catch (error) {\n reportCallbackError(name, error);\n }\n};\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 invokeMcpOAuthCallback(\"onError\", optsRef.current.onError, error);\n return;\n }\n\n invokeMcpOAuthCallback(\n \"onComplete\",\n optsRef.current.onComplete,\n serverId,\n );\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","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 +1 @@
1
- {"version":3,"file":"McpAddFormRoot.d.ts","names":[],"sources":["../../../src/primitives/addForm/McpAddFormRoot.tsx"],"mappings":";;;kBAuCiB;OACH,UAAU,oBAAoB,UAAU;OACxC,QAAQ,KAClB,gCAAgC,UAAU;IAG1C,eAAe;IACf;;;cAIS,yCAAuB,0BAAA,KAAA,qBAAA,gBAAA,mCAAA,mBAAA;;;EALlB,eAAC;EACJ;oBA4Fb,cAAA"}
1
+ {"version":3,"file":"McpAddFormRoot.d.ts","names":[],"sources":["../../../src/primitives/addForm/McpAddFormRoot.tsx"],"mappings":";;;kBAwCiB;OACH,UAAU,oBAAoB,UAAU;OACxC,QAAQ,KAClB,gCAAgC,UAAU;IAG1C,eAAe;IACf;;;cAIS,yCAAuB,0BAAA,KAAA,qBAAA,gBAAA,mCAAA,mBAAA;;;EALlB,eAAC;EACJ;oBA4Fb,cAAA"}
@@ -1,4 +1,5 @@
1
1
  import { AddFormContext } from "./context.js";
2
+ import { invokeMcpCallback } from "../../utils/invokeMcpCallback.js";
2
3
  import { useAui } from "@assistant-ui/store";
3
4
  import { forwardRef, useCallback, useMemo, useState } from "@assistant-ui/tap/react-shim";
4
5
  import { Primitive } from "@radix-ui/react-primitive";
@@ -91,7 +92,7 @@ const McpAddFormPrimitiveRoot = forwardRef(({ onSubmitted, onCancel, ...props },
91
92
  auth: buildAuth()
92
93
  });
93
94
  setState(INITIAL);
94
- onSubmitted?.(id);
95
+ invokeMcpCallback("onSubmitted", onSubmitted, id);
95
96
  } catch (err) {
96
97
  setState((p_3) => ({
97
98
  ...p_3,
@@ -1 +1 @@
1
- {"version":3,"file":"McpAddFormRoot.js","names":["ComponentPropsWithoutRef","ComponentRef","FormEventHandler","forwardRef","useCallback","useMemo","useState","Primitive","useAui","AddFormContext","AddFormState","MCPAuthConfig","INITIAL","name","url","authType","bearerToken","scopes","submitting","error","validateUrl","raw","trimmed","trim","parsed","URL","protocol","McpAddFormPrimitiveRoot","Element","form","Props","Omit","onSubmitted","id","onCancel","props","ref","aui","state","setState","setField","key","K","value","prev","reset","buildAuth","type","token","undefined","scopeList","split","map","s","filter","Boolean","length","submit","p","urlResult","mcp","addCustomServer","auth","err","Error","message","String","cancel","onFormSubmit","HTMLFormElement","e","preventDefault","displayName"],"sources":["../../../src/primitives/addForm/McpAddFormRoot.tsx"],"sourcesContent":["import {\n type ComponentPropsWithoutRef,\n type ComponentRef,\n type FormEventHandler,\n forwardRef,\n useCallback,\n useMemo,\n useState,\n} from \"react\";\nimport { Primitive } from \"@radix-ui/react-primitive\";\nimport { useAui } from \"@assistant-ui/store\";\nimport { AddFormContext, type AddFormState } from \"./context\";\nimport type { MCPAuthConfig } from \"../../mcp-scope\";\n\nconst INITIAL: AddFormState = {\n name: \"\",\n url: \"\",\n authType: \"oauth\",\n bearerToken: \"\",\n scopes: \"\",\n submitting: false,\n error: null,\n};\n\nfunction validateUrl(raw: string): { url: string } | { error: string } {\n const trimmed = raw.trim();\n if (!trimmed) return { error: \"URL is required\" };\n let parsed: URL;\n try {\n parsed = new URL(trimmed);\n } catch {\n return { error: \"Invalid URL\" };\n }\n if (parsed.protocol !== \"http:\" && parsed.protocol !== \"https:\") {\n return { error: \"URL must be http(s)\" };\n }\n return { url: trimmed };\n}\n\nexport namespace McpAddFormPrimitiveRoot {\n export type Element = ComponentRef<typeof Primitive.form>;\n export type Props = Omit<\n ComponentPropsWithoutRef<typeof Primitive.form>,\n \"onSubmit\"\n > & {\n onSubmitted?: (id: string) => void;\n onCancel?: () => void;\n };\n}\n\nexport const McpAddFormPrimitiveRoot = forwardRef<\n McpAddFormPrimitiveRoot.Element,\n McpAddFormPrimitiveRoot.Props\n>(({ onSubmitted, onCancel, ...props }, ref) => {\n const aui = useAui();\n const [state, setState] = useState<AddFormState>(INITIAL);\n\n const setField = useCallback(\n <K extends keyof AddFormState>(key: K, value: AddFormState[K]) => {\n setState((prev) => ({ ...prev, [key]: value }));\n },\n [],\n );\n\n const reset = useCallback(() => setState(INITIAL), []);\n\n const buildAuth = useCallback((): MCPAuthConfig => {\n switch (state.authType) {\n case \"none\":\n return { type: \"none\" };\n case \"bearer\":\n return { type: \"bearer\", token: state.bearerToken || undefined };\n case \"oauth\": {\n const scopeList = state.scopes\n .split(/[\\s,]+/)\n .map((s) => s.trim())\n .filter(Boolean);\n return {\n type: \"oauth\",\n scopes: scopeList.length > 0 ? scopeList : undefined,\n };\n }\n }\n }, [state.authType, state.bearerToken, state.scopes]);\n\n const submit = useCallback(async () => {\n if (state.submitting) return;\n if (!state.name.trim()) {\n setState((p) => ({ ...p, error: \"Name is required\" }));\n return;\n }\n if (state.authType === \"bearer\" && !state.bearerToken.trim()) {\n setState((p) => ({ ...p, error: \"Bearer token is required\" }));\n return;\n }\n const urlResult = validateUrl(state.url);\n if (\"error\" in urlResult) {\n setState((p) => ({ ...p, error: urlResult.error }));\n return;\n }\n setState((p) => ({ ...p, submitting: true, error: null }));\n try {\n const id = await aui.mcp.addCustomServer({\n name: state.name.trim(),\n url: urlResult.url,\n auth: buildAuth(),\n });\n setState(INITIAL);\n onSubmitted?.(id);\n } catch (err) {\n setState((p) => ({\n ...p,\n submitting: false,\n error: err instanceof Error ? err.message : String(err),\n }));\n }\n }, [aui, buildAuth, onSubmitted, state]);\n\n const cancel = useCallback(() => {\n setState(INITIAL);\n onCancel?.();\n }, [onCancel]);\n\n const value = useMemo(\n () => ({ state, setField, reset, submit, cancel }),\n [state, setField, reset, submit, cancel],\n );\n\n const onFormSubmit: FormEventHandler<HTMLFormElement> = (e) => {\n e.preventDefault();\n void submit();\n };\n\n return (\n <AddFormContext.Provider value={value}>\n <Primitive.form {...props} ref={ref} onSubmit={onFormSubmit} />\n </AddFormContext.Provider>\n );\n});\n\nMcpAddFormPrimitiveRoot.displayName = \"McpAddFormPrimitive.Root\";\n"],"mappings":"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"}
1
+ {"version":3,"file":"McpAddFormRoot.js","names":["ComponentPropsWithoutRef","ComponentRef","FormEventHandler","forwardRef","useCallback","useMemo","useState","Primitive","useAui","AddFormContext","AddFormState","MCPAuthConfig","invokeMcpCallback","INITIAL","name","url","authType","bearerToken","scopes","submitting","error","validateUrl","raw","trimmed","trim","parsed","URL","protocol","McpAddFormPrimitiveRoot","Element","form","Props","Omit","onSubmitted","id","onCancel","props","ref","aui","state","setState","setField","key","K","value","prev","reset","buildAuth","type","token","undefined","scopeList","split","map","s","filter","Boolean","length","submit","p","urlResult","mcp","addCustomServer","auth","err","Error","message","String","cancel","onFormSubmit","HTMLFormElement","e","preventDefault","displayName"],"sources":["../../../src/primitives/addForm/McpAddFormRoot.tsx"],"sourcesContent":["import {\n type ComponentPropsWithoutRef,\n type ComponentRef,\n type FormEventHandler,\n forwardRef,\n useCallback,\n useMemo,\n useState,\n} from \"react\";\nimport { Primitive } from \"@radix-ui/react-primitive\";\nimport { useAui } from \"@assistant-ui/store\";\nimport { AddFormContext, type AddFormState } from \"./context\";\nimport type { MCPAuthConfig } from \"../../mcp-scope\";\nimport { invokeMcpCallback } from \"../../utils/invokeMcpCallback\";\n\nconst INITIAL: AddFormState = {\n name: \"\",\n url: \"\",\n authType: \"oauth\",\n bearerToken: \"\",\n scopes: \"\",\n submitting: false,\n error: null,\n};\n\nfunction validateUrl(raw: string): { url: string } | { error: string } {\n const trimmed = raw.trim();\n if (!trimmed) return { error: \"URL is required\" };\n let parsed: URL;\n try {\n parsed = new URL(trimmed);\n } catch {\n return { error: \"Invalid URL\" };\n }\n if (parsed.protocol !== \"http:\" && parsed.protocol !== \"https:\") {\n return { error: \"URL must be http(s)\" };\n }\n return { url: trimmed };\n}\n\nexport namespace McpAddFormPrimitiveRoot {\n export type Element = ComponentRef<typeof Primitive.form>;\n export type Props = Omit<\n ComponentPropsWithoutRef<typeof Primitive.form>,\n \"onSubmit\"\n > & {\n onSubmitted?: (id: string) => void;\n onCancel?: () => void;\n };\n}\n\nexport const McpAddFormPrimitiveRoot = forwardRef<\n McpAddFormPrimitiveRoot.Element,\n McpAddFormPrimitiveRoot.Props\n>(({ onSubmitted, onCancel, ...props }, ref) => {\n const aui = useAui();\n const [state, setState] = useState<AddFormState>(INITIAL);\n\n const setField = useCallback(\n <K extends keyof AddFormState>(key: K, value: AddFormState[K]) => {\n setState((prev) => ({ ...prev, [key]: value }));\n },\n [],\n );\n\n const reset = useCallback(() => setState(INITIAL), []);\n\n const buildAuth = useCallback((): MCPAuthConfig => {\n switch (state.authType) {\n case \"none\":\n return { type: \"none\" };\n case \"bearer\":\n return { type: \"bearer\", token: state.bearerToken || undefined };\n case \"oauth\": {\n const scopeList = state.scopes\n .split(/[\\s,]+/)\n .map((s) => s.trim())\n .filter(Boolean);\n return {\n type: \"oauth\",\n scopes: scopeList.length > 0 ? scopeList : undefined,\n };\n }\n }\n }, [state.authType, state.bearerToken, state.scopes]);\n\n const submit = useCallback(async () => {\n if (state.submitting) return;\n if (!state.name.trim()) {\n setState((p) => ({ ...p, error: \"Name is required\" }));\n return;\n }\n if (state.authType === \"bearer\" && !state.bearerToken.trim()) {\n setState((p) => ({ ...p, error: \"Bearer token is required\" }));\n return;\n }\n const urlResult = validateUrl(state.url);\n if (\"error\" in urlResult) {\n setState((p) => ({ ...p, error: urlResult.error }));\n return;\n }\n setState((p) => ({ ...p, submitting: true, error: null }));\n try {\n const id = await aui.mcp.addCustomServer({\n name: state.name.trim(),\n url: urlResult.url,\n auth: buildAuth(),\n });\n setState(INITIAL);\n invokeMcpCallback(\"onSubmitted\", onSubmitted, id);\n } catch (err) {\n setState((p) => ({\n ...p,\n submitting: false,\n error: err instanceof Error ? err.message : String(err),\n }));\n }\n }, [aui, buildAuth, onSubmitted, state]);\n\n const cancel = useCallback(() => {\n setState(INITIAL);\n onCancel?.();\n }, [onCancel]);\n\n const value = useMemo(\n () => ({ state, setField, reset, submit, cancel }),\n [state, setField, reset, submit, cancel],\n );\n\n const onFormSubmit: FormEventHandler<HTMLFormElement> = (e) => {\n e.preventDefault();\n void submit();\n };\n\n return (\n <AddFormContext.Provider value={value}>\n <Primitive.form {...props} ref={ref} onSubmit={onFormSubmit} />\n </AddFormContext.Provider>\n );\n});\n\nMcpAddFormPrimitiveRoot.displayName = \"McpAddFormPrimitive.Root\";\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"McpManagerResource.d.ts","names":[],"sources":["../../src/resources/McpManagerResource.ts"],"mappings":";;;;KAqBY;EACV,aAAa;EACb,UAAU;;EAEV;;EAEA;;EAEA;;cAwRW,gDAAkB,SAAA,sBAAA,OAAA"}
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"}
@@ -5,6 +5,7 @@ import { attachTransformScopes, useAssistantClientRef, useClientLookup } from "@
5
5
  import { c } from "@assistant-ui/tap/react-shim/compiler-runtime";
6
6
  import { useEffect, useEffectEvent, useRef, useState } from "@assistant-ui/tap/react-shim";
7
7
  import { resource, useResource, withKey } from "@assistant-ui/tap";
8
+ import { useAssistantScopeEffect } from "@assistant-ui/store/client";
8
9
  import { ModelContext } from "@assistant-ui/core/store";
9
10
  //#region src/resources/McpManagerResource.ts
10
11
  function defaultRedirectUri() {
@@ -23,7 +24,7 @@ const persistCustomServers = async (storage, records) => {
23
24
  }
24
25
  };
25
26
  const useMcpManagerResource = (props) => {
26
- const $ = c(72);
27
+ const $ = c(73);
27
28
  const connectors = props.connectors ?? NO_CONNECTORS;
28
29
  const autoConnect = props.autoConnect ?? true;
29
30
  let t0;
@@ -248,55 +249,55 @@ const useMcpManagerResource = (props) => {
248
249
  const toolkit = out;
249
250
  const clientRef = useAssistantClientRef();
250
251
  let t15;
251
- let t16;
252
252
  if ($[46] !== clientRef || $[47] !== toolkit) {
253
253
  t15 = () => {
254
254
  const client = clientRef.current;
255
255
  if (!client) return;
256
256
  return client.modelContext.register({ getModelContext: () => ({ tools: toolkit }) });
257
257
  };
258
- t16 = [toolkit, clientRef];
259
258
  $[46] = clientRef;
260
259
  $[47] = toolkit;
261
260
  $[48] = t15;
262
- $[49] = t16;
263
- } else {
264
- t15 = $[48];
265
- t16 = $[49];
266
- }
267
- useEffect(t15, t16);
261
+ } else t15 = $[48];
262
+ let t16;
263
+ if ($[49] !== toolkit) {
264
+ t16 = [toolkit];
265
+ $[49] = toolkit;
266
+ $[50] = t16;
267
+ } else t16 = $[50];
268
+ useAssistantScopeEffect("modelContext", t15, t16);
268
269
  let t17;
269
- if ($[50] !== lookup || $[51] !== state) {
270
+ if ($[51] !== lookup || $[52] !== state) {
270
271
  t17 = (kind, index) => {
271
272
  const list = kind === "connector" ? state.connectors : state.customServers;
272
273
  const entry = list[index];
273
274
  if (!entry) throw new Error(`McpManagerResource: no ${kind} at index ${index} (length ${list.length})`);
274
275
  return lookup.get({ key: entry.id });
275
276
  };
276
- $[50] = lookup;
277
- $[51] = state;
278
- $[52] = t17;
279
- } else t17 = $[52];
277
+ $[51] = lookup;
278
+ $[52] = state;
279
+ $[53] = t17;
280
+ } else t17 = $[53];
280
281
  const serverByKind = t17;
281
282
  let t18;
282
- if ($[53] !== state) {
283
+ if ($[54] !== state) {
283
284
  t18 = () => state;
284
- $[53] = state;
285
- $[54] = t18;
286
- } else t18 = $[54];
285
+ $[54] = state;
286
+ $[55] = t18;
287
+ } else t18 = $[55];
287
288
  let t19;
288
- if ($[55] !== lookup || $[56] !== serverByKind) {
289
+ if ($[56] !== lookup || $[57] !== serverByKind) {
289
290
  t19 = (query) => {
290
291
  if ("id" in query) return lookup.get({ key: query.id });
291
292
  return serverByKind(query.kind, query.index);
292
293
  };
293
- $[55] = lookup;
294
- $[56] = serverByKind;
295
- $[57] = t19;
296
- } else t19 = $[57];
294
+ $[56] = lookup;
295
+ $[57] = serverByKind;
296
+ $[58] = t19;
297
+ } else t19 = $[58];
297
298
  let t20;
298
299
  let t21;
299
- if ($[58] !== serverByKind) {
300
+ if ($[59] !== serverByKind) {
300
301
  t20 = (t22) => {
301
302
  const { index: index_0 } = t22;
302
303
  return serverByKind("connector", index_0);
@@ -305,15 +306,15 @@ const useMcpManagerResource = (props) => {
305
306
  const { index: index_1 } = t23;
306
307
  return serverByKind("custom", index_1);
307
308
  };
308
- $[58] = serverByKind;
309
- $[59] = t20;
310
- $[60] = t21;
309
+ $[59] = serverByKind;
310
+ $[60] = t20;
311
+ $[61] = t21;
311
312
  } else {
312
- t20 = $[59];
313
- t21 = $[60];
313
+ t20 = $[60];
314
+ t21 = $[61];
314
315
  }
315
316
  let t22;
316
- if ($[61] === Symbol.for("react.memo_cache_sentinel")) {
317
+ if ($[62] === Symbol.for("react.memo_cache_sentinel")) {
317
318
  t22 = async (t23) => {
318
319
  const { name, url, auth, connectionTimeout: connectionTimeout_0, cache, elicitation } = t23;
319
320
  const record = {
@@ -329,10 +330,10 @@ const useMcpManagerResource = (props) => {
329
330
  setCustomServers((prev_1) => [...prev_1, record]);
330
331
  return record.id;
331
332
  };
332
- $[61] = t22;
333
- } else t22 = $[61];
333
+ $[62] = t22;
334
+ } else t22 = $[62];
334
335
  let t23;
335
- if ($[62] !== lookup || $[63] !== state || $[64] !== storage) {
336
+ if ($[63] !== lookup || $[64] !== state || $[65] !== storage) {
336
337
  t23 = async (id) => {
337
338
  if (state.connectors.some((c_1) => c_1.id === id)) throw new Error(`Cannot remove connector "${id}" — connectors are app-defined and not removable. Use a custom server id instead.`);
338
339
  try {
@@ -342,13 +343,13 @@ const useMcpManagerResource = (props) => {
342
343
  setCustomServers((prev_2) => prev_2.filter((s_3) => s_3.id !== id));
343
344
  }
344
345
  };
345
- $[62] = lookup;
346
- $[63] = state;
347
- $[64] = storage;
348
- $[65] = t23;
349
- } else t23 = $[65];
346
+ $[63] = lookup;
347
+ $[64] = state;
348
+ $[65] = storage;
349
+ $[66] = t23;
350
+ } else t23 = $[66];
350
351
  let t24;
351
- if ($[66] !== t18 || $[67] !== t19 || $[68] !== t20 || $[69] !== t21 || $[70] !== t23) {
352
+ if ($[67] !== t18 || $[68] !== t19 || $[69] !== t20 || $[70] !== t21 || $[71] !== t23) {
352
353
  t24 = {
353
354
  getState: t18,
354
355
  server: t19,
@@ -357,13 +358,13 @@ const useMcpManagerResource = (props) => {
357
358
  addCustomServer: t22,
358
359
  removeServer: t23
359
360
  };
360
- $[66] = t18;
361
- $[67] = t19;
362
- $[68] = t20;
363
- $[69] = t21;
364
- $[70] = t23;
365
- $[71] = t24;
366
- } else t24 = $[71];
361
+ $[67] = t18;
362
+ $[68] = t19;
363
+ $[69] = t20;
364
+ $[70] = t21;
365
+ $[71] = t23;
366
+ $[72] = t24;
367
+ } else t24 = $[72];
367
368
  return t24;
368
369
  };
369
370
  const McpManagerResource = resource(useMcpManagerResource);
@@ -1 +1 @@
1
- {"version":3,"file":"McpManagerResource.js","names":["useState","useEffect","useMemo","useEffectEvent","useRef","useResource","resource","withKey","useClientLookup","useAssistantClientRef","attachTransformScopes","ClientOutput","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","t16","client","modelContext","register","getModelContext","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 { 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 useEffect(() => {\n const client = clientRef.current;\n if (!client) return;\n return client.modelContext.register({\n getModelContext: () => ({ tools: toolkit }),\n });\n }, [toolkit, clientRef]);\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":"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"}
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":"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"}
@@ -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;;cA8kBL,+CAAiB,SAAA,4BAAA,OAAA"}
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"}
@@ -268,8 +268,18 @@ const useMcpServerResource = (props) => {
268
268
  doConnect();
269
269
  return;
270
270
  }
271
- const persisted_0 = await props.storage.loadAuthState(props.id);
272
- if (signal.cancelled) return;
271
+ const generation_4 = connectionGenerationRef.current;
272
+ let persisted_0;
273
+ try {
274
+ persisted_0 = await props.storage.loadAuthState(props.id);
275
+ } catch (error_2) {
276
+ if (signal.cancelled || !isCurrentConnection(generation_4)) return;
277
+ const message_0 = error_2 instanceof Error ? error_2.message : String(error_2);
278
+ setLastError({ message: `MCP server "${props.id}" failed to load saved authentication: ${message_0}` });
279
+ setConnectionState("error");
280
+ return;
281
+ }
282
+ if (signal.cancelled || !isCurrentConnection(generation_4)) return;
273
283
  if (props.auth.type === "oauth") {
274
284
  if (!persisted_0?.tokens) return;
275
285
  } else if (!persisted_0?.token) return;
@@ -366,7 +376,7 @@ const useMcpServerResource = (props) => {
366
376
  }
367
377
  const errors_0 = validateElicitationContent(entry_1.requestedSchema, response.content);
368
378
  if (errors_0.length > 0) {
369
- const properties = [...new Set(errors_0.map((error_2) => error_2.property))];
379
+ const properties = [...new Set(errors_0.map((error_3) => error_3.property))];
370
380
  setPendingElicitationError(id_3, {
371
381
  message: `Invalid elicitation content: ${properties.join(", ")}.`,
372
382
  properties