@assistant-ui/react-mcp 0.0.22 → 0.1.0

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 (94) hide show
  1. package/dist/auth/createOAuthProvider.d.ts +1 -1
  2. package/dist/auth/createOAuthProvider.js.map +1 -1
  3. package/dist/auth/types.d.ts +1 -1
  4. package/dist/index.d.ts +3 -2
  5. package/dist/index.js +2 -1
  6. package/dist/mcp-scope.d.ts +32 -1
  7. package/dist/mcp-scope.d.ts.map +1 -1
  8. package/dist/primitives/elicitation/McpElicitationPrimitiveAccept.d.ts +13 -0
  9. package/dist/primitives/elicitation/McpElicitationPrimitiveAccept.d.ts.map +1 -0
  10. package/dist/primitives/elicitation/McpElicitationPrimitiveAccept.js +106 -0
  11. package/dist/primitives/elicitation/McpElicitationPrimitiveAccept.js.map +1 -0
  12. package/dist/primitives/elicitation/McpElicitationPrimitiveCancel.d.ts +13 -0
  13. package/dist/primitives/elicitation/McpElicitationPrimitiveCancel.d.ts.map +1 -0
  14. package/dist/primitives/elicitation/McpElicitationPrimitiveCancel.js +43 -0
  15. package/dist/primitives/elicitation/McpElicitationPrimitiveCancel.js.map +1 -0
  16. package/dist/primitives/elicitation/McpElicitationPrimitiveDecline.d.ts +13 -0
  17. package/dist/primitives/elicitation/McpElicitationPrimitiveDecline.d.ts.map +1 -0
  18. package/dist/primitives/elicitation/McpElicitationPrimitiveDecline.js +43 -0
  19. package/dist/primitives/elicitation/McpElicitationPrimitiveDecline.js.map +1 -0
  20. package/dist/primitives/elicitation/McpElicitationPrimitiveError.d.ts +13 -0
  21. package/dist/primitives/elicitation/McpElicitationPrimitiveError.d.ts.map +1 -0
  22. package/dist/primitives/elicitation/McpElicitationPrimitiveError.js +38 -0
  23. package/dist/primitives/elicitation/McpElicitationPrimitiveError.js.map +1 -0
  24. package/dist/primitives/elicitation/McpElicitationPrimitiveFields.d.ts +12 -0
  25. package/dist/primitives/elicitation/McpElicitationPrimitiveFields.d.ts.map +1 -0
  26. package/dist/primitives/elicitation/McpElicitationPrimitiveFields.js +53 -0
  27. package/dist/primitives/elicitation/McpElicitationPrimitiveFields.js.map +1 -0
  28. package/dist/primitives/elicitation/McpElicitationPrimitiveItems.d.ts +13 -0
  29. package/dist/primitives/elicitation/McpElicitationPrimitiveItems.d.ts.map +1 -0
  30. package/dist/primitives/elicitation/McpElicitationPrimitiveItems.js +96 -0
  31. package/dist/primitives/elicitation/McpElicitationPrimitiveItems.js.map +1 -0
  32. package/dist/primitives/elicitation/McpElicitationPrimitiveMessage.d.ts +13 -0
  33. package/dist/primitives/elicitation/McpElicitationPrimitiveMessage.d.ts.map +1 -0
  34. package/dist/primitives/elicitation/McpElicitationPrimitiveMessage.js +29 -0
  35. package/dist/primitives/elicitation/McpElicitationPrimitiveMessage.js.map +1 -0
  36. package/dist/primitives/elicitation/McpElicitationPrimitiveRoot.d.ts +13 -0
  37. package/dist/primitives/elicitation/McpElicitationPrimitiveRoot.d.ts.map +1 -0
  38. package/dist/primitives/elicitation/McpElicitationPrimitiveRoot.js +28 -0
  39. package/dist/primitives/elicitation/McpElicitationPrimitiveRoot.js.map +1 -0
  40. package/dist/primitives/elicitation/context.d.ts +21 -0
  41. package/dist/primitives/elicitation/context.d.ts.map +1 -0
  42. package/dist/primitives/elicitation/context.js +21 -0
  43. package/dist/primitives/elicitation/context.js.map +1 -0
  44. package/dist/primitives/elicitation/initialElicitationDraft.d.ts +5 -0
  45. package/dist/primitives/elicitation/initialElicitationDraft.d.ts.map +1 -0
  46. package/dist/primitives/elicitation/initialElicitationDraft.js +27 -0
  47. package/dist/primitives/elicitation/initialElicitationDraft.js.map +1 -0
  48. package/dist/primitives/elicitation/prepareElicitationContent.d.ts +9 -0
  49. package/dist/primitives/elicitation/prepareElicitationContent.d.ts.map +1 -0
  50. package/dist/primitives/elicitation/prepareElicitationContent.js +46 -0
  51. package/dist/primitives/elicitation/prepareElicitationContent.js.map +1 -0
  52. package/dist/primitives/elicitation.d.ts +15 -0
  53. package/dist/primitives/elicitation.d.ts.map +1 -0
  54. package/dist/primitives/elicitation.js +27 -0
  55. package/dist/primitives/elicitation.js.map +1 -0
  56. package/dist/resources/McpManagerResource.d.ts.map +1 -1
  57. package/dist/resources/McpManagerResource.js +17 -3
  58. package/dist/resources/McpManagerResource.js.map +1 -1
  59. package/dist/resources/McpServerResource.d.ts +4 -0
  60. package/dist/resources/McpServerResource.d.ts.map +1 -1
  61. package/dist/resources/McpServerResource.js +153 -42
  62. package/dist/resources/McpServerResource.js.map +1 -1
  63. package/dist/resources/storage/McpLocalStorage.js +1 -1
  64. package/dist/resources/storage/McpLocalStorage.js.map +1 -1
  65. package/dist/resources/validateElicitationContent.d.ts +9 -0
  66. package/dist/resources/validateElicitationContent.d.ts.map +1 -0
  67. package/dist/resources/validateElicitationContent.js +47 -0
  68. package/dist/resources/validateElicitationContent.js.map +1 -0
  69. package/package.json +7 -6
  70. package/src/auth/createOAuthProvider.ts +2 -2
  71. package/src/auth/types.ts +1 -1
  72. package/src/index.ts +4 -0
  73. package/src/mcp-scope.ts +32 -0
  74. package/src/primitives/elicitation/McpElicitationPrimitiveAccept.tsx +48 -0
  75. package/src/primitives/elicitation/McpElicitationPrimitiveCancel.tsx +37 -0
  76. package/src/primitives/elicitation/McpElicitationPrimitiveDecline.tsx +37 -0
  77. package/src/primitives/elicitation/McpElicitationPrimitiveError.tsx +31 -0
  78. package/src/primitives/elicitation/McpElicitationPrimitiveFields.tsx +56 -0
  79. package/src/primitives/elicitation/McpElicitationPrimitiveItems.tsx +58 -0
  80. package/src/primitives/elicitation/McpElicitationPrimitiveMessage.tsx +26 -0
  81. package/src/primitives/elicitation/McpElicitationPrimitiveRoot.tsx +24 -0
  82. package/src/primitives/elicitation/context.tsx +45 -0
  83. package/src/primitives/elicitation/initialElicitationDraft.test.ts +34 -0
  84. package/src/primitives/elicitation/initialElicitationDraft.ts +39 -0
  85. package/src/primitives/elicitation/prepareElicitationContent.test.ts +415 -0
  86. package/src/primitives/elicitation/prepareElicitationContent.ts +116 -0
  87. package/src/primitives/elicitation.ts +14 -0
  88. package/src/resources/McpManagerResource.test.ts +173 -3
  89. package/src/resources/McpManagerResource.ts +37 -3
  90. package/src/resources/McpServerResource.test.ts +735 -4
  91. package/src/resources/McpServerResource.ts +237 -29
  92. package/src/resources/storage/McpLocalStorage.ts +1 -1
  93. package/src/resources/validateElicitationContent.test.ts +123 -0
  94. package/src/resources/validateElicitationContent.ts +79 -0
@@ -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","MCPStorageElement","assertUniqueServerIds","MCPAuthConfig","MCPConnector","MCPCustomServerRecord","MCPManagerState","McpManagerResourceProps","connectors","storage","oauthRedirectUri","autoConnect","connectionTimeout","defaultRedirectUri","window","location","origin","NO_CONNECTORS","useMcpManagerResource","props","$","_c","t0","redirectUri","t1","storageElement","t2","Symbol","for","customServers","setCustomServers","isHydrated","setIsHydrated","hydratedRef","t3","signal","markHydrated","cancelled","current","records","loadCustomServers","t4","error","prev","length","persistedIds","Set","map","_temp","filter","r_0","has","r","id","hydrate","signal_0","t5","t6","records_0","saveCustomServers","persistCustomServers","t7","t8","_temp2","_temp3","t9","t10","c_0","c","kind","name","url","icon","auth","onRemove","_temp4","connectorElements","t11","s_0","s","prev_0","x","customElements","serverElements","lookup","all","state","_temp5","_temp6","t12","servers","out","server","connectionState","tool","tools","fullName","type","description","undefined","parameters","inputSchema","execute","args","get","key","callTool","toolkit","clientRef","t13","t14","client","modelContext","register","getModelContext","t15","index","list","entry","Error","serverByKind","t16","t17","query","t18","t19","t20","index_0","t21","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","t22","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 { 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 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\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 markHydrated();\n throw error;\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 const persistCustomServers = useEffectEvent(\n async (records: MCPCustomServerRecord[]) => {\n if (!hydratedRef.current) return;\n await storage.saveCustomServers(records);\n },\n );\n\n useEffect(() => {\n void persistCustomServers(customServers);\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 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 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 ({ name, url, auth, connectionTimeout }) => {\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 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","ModelContext","Tool","McpServerResource","McpLocalStorage","MCPStorageElement","assertUniqueServerIds","MCPAuthConfig","MCPConnector","MCPCustomServerRecord","MCPManagerState","McpManagerResourceProps","connectors","storage","oauthRedirectUri","autoConnect","connectionTimeout","defaultRedirectUri","window","location","origin","NO_CONNECTORS","reportCustomStorageFailure","operation","error","console","useMcpManagerResource","props","$","_c","t0","redirectUri","t1","storageElement","t2","Symbol","for","customServers","setCustomServers","isHydrated","setIsHydrated","hydratedRef","t3","signal","markHydrated","cancelled","current","records","loadCustomServers","t4","prev","length","persistedIds","Set","map","_temp","filter","r_0","has","r","id","hydrate","signal_0","t5","t6","records_0","saveCustomServers","t7","persistCustomServers","t8","_temp2","_temp3","t9","t10","c_0","c","kind","name","url","icon","auth","cache","undefined","elicitation","onRemove","_temp4","connectorElements","t11","s_0","s","prev_0","x","customElements","serverElements","lookup","all","state","_temp5","_temp6","t12","servers","out","server","connectionState","tool","tools","fullName","type","description","parameters","inputSchema","execute","args","get","key","callTool","toolkit","clientRef","t13","t14","client","modelContext","register","getModelContext","t15","index","list","entry","Error","serverByKind","t16","t17","query","t18","t19","t20","index_0","t21","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","t22","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 { 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 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\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 const persistCustomServers = useEffectEvent(\n async (records: MCPCustomServerRecord[]) => {\n if (!hydratedRef.current) return;\n try {\n await storage.saveCustomServers(records);\n } catch (error) {\n reportCustomStorageFailure(\"save\", error);\n }\n },\n );\n\n useEffect(() => {\n void persistCustomServers(customServers);\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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"}
@@ -13,6 +13,10 @@ type McpServerResourceProps = {
13
13
  redirectUri: string;
14
14
  autoConnect: boolean;
15
15
  connectionTimeout?: number | undefined;
16
+ cache?: {
17
+ readonly defaultTtlMs?: number;
18
+ } | undefined;
19
+ readonly elicitation?: boolean;
16
20
  onRemove: () => Promise<void>;
17
21
  };
18
22
  declare const McpServerResource: import("@assistant-ui/tap").Resource<ClientOutput<"mcpServer">, [props: McpServerResourceProps]>;
@@ -1 +1 @@
1
- {"version":3,"file":"McpServerResource.d.ts","names":[],"sources":["../../src/resources/McpServerResource.ts"],"mappings":";;;;KAsBY;EACV;EACA,MAAM;EACN;EACA;EACA;EACA,MAAM;EACN,SAAS;EACT;EACA;EACA;EACA,gBAAgB;;cA8XL,+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;;cAukBL,+CAAiB,SAAA,4BAAA,OAAA"}
@@ -1,11 +1,10 @@
1
1
  import { assertValidServerId } from "../utils/serverId.js";
2
2
  import { createOAuthProvider } from "../auth/createOAuthProvider.js";
3
3
  import { buildHeaders } from "../auth/buildHeaders.js";
4
+ import { validateElicitationContent } from "./validateElicitationContent.js";
4
5
  import { useEffect, useEffectEvent, useMemo, useRef, useState } from "@assistant-ui/tap/react-shim";
5
6
  import { resource } from "@assistant-ui/tap";
6
- import { Client } from "@modelcontextprotocol/sdk/client/index.js";
7
- import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
8
- import { UnauthorizedError } from "@modelcontextprotocol/sdk/client/auth.js";
7
+ import { Client, StreamableHTTPClientTransport, UnauthorizedError } from "@modelcontextprotocol/client";
9
8
  //#region src/resources/McpServerResource.ts
10
9
  const useMcpServerResource = (props) => {
11
10
  assertValidServerId(props.id);
@@ -13,11 +12,13 @@ const useMcpServerResource = (props) => {
13
12
  const [tools, setTools] = useState([]);
14
13
  const [lastError, setLastError] = useState(null);
15
14
  const [authorizationUrl, setAuthorizationUrl] = useState(null);
15
+ const [pendingElicitations, setPendingElicitations] = useState([]);
16
16
  const clientRef = useRef(null);
17
17
  const transportRef = useRef(null);
18
18
  const pendingTransportRef = useRef(null);
19
19
  const transportCloseQueueRef = useRef(Promise.resolve());
20
20
  const connectionGenerationRef = useRef(0);
21
+ const elicitationResolversRef = useRef(/* @__PURE__ */ new Map());
21
22
  const pendingDisposalRef = useRef(null);
22
23
  const mountedRef = useRef(true);
23
24
  const closeTransportSafely = async (transport) => {
@@ -37,7 +38,28 @@ const useMcpServerResource = (props) => {
37
38
  pendingTransportRef.current = null;
38
39
  await closeQueuedTransports(transport_0 ? [transport_0] : []);
39
40
  };
41
+ const resolvePendingElicitation = (id, result) => {
42
+ const entry = elicitationResolversRef.current.get(id);
43
+ if (!entry) return false;
44
+ elicitationResolversRef.current.delete(id);
45
+ entry.signal.removeEventListener("abort", entry.onAbort);
46
+ setPendingElicitations((current) => current.filter((elicitation) => elicitation.id !== id));
47
+ entry.resolve(result);
48
+ return true;
49
+ };
50
+ const setPendingElicitationError = (id_0, error) => {
51
+ if (!elicitationResolversRef.current.has(id_0)) return false;
52
+ setPendingElicitations((current_0) => current_0.map((elicitation_0) => elicitation_0.id === id_0 ? {
53
+ ...elicitation_0,
54
+ error
55
+ } : elicitation_0));
56
+ return true;
57
+ };
58
+ const cancelPendingElicitations = () => {
59
+ for (const [id_1] of elicitationResolversRef.current) resolvePendingElicitation(id_1, { action: "cancel" });
60
+ };
40
61
  const closeTransports = async () => {
62
+ cancelPendingElicitations();
41
63
  const pendingTransport = pendingTransportRef.current;
42
64
  const activeTransport = transportRef.current;
43
65
  pendingTransportRef.current = null;
@@ -83,19 +105,7 @@ const useMcpServerResource = (props) => {
83
105
  }
84
106
  return new StreamableHTTPClientTransport(new URL(props.url));
85
107
  });
86
- const finalizeConnect = useEffectEvent(async (transport_2, generation_0) => {
87
- const client = new Client({
88
- name: "assistant-ui-mcp",
89
- version: "0.0.0"
90
- });
91
- const startedAt_0 = Date.now();
92
- await withConnectionTimeout(client.connect(transport_2), "connecting", startedAt_0);
93
- if (!isCurrentConnection(generation_0)) return false;
94
- const list = await withConnectionTimeout(client.listTools(), "listing tools", startedAt_0);
95
- if (!isCurrentConnection(generation_0)) return false;
96
- pendingTransportRef.current = null;
97
- clientRef.current = client;
98
- transportRef.current = transport_2;
108
+ const applyToolsList = useEffectEvent((list) => {
99
109
  setTools(list.tools.map((t) => {
100
110
  const info = {
101
111
  name: t.name,
@@ -104,13 +114,77 @@ const useMcpServerResource = (props) => {
104
114
  if (t.description !== void 0) info.description = t.description;
105
115
  return info;
106
116
  }));
117
+ });
118
+ const syncTools = useEffectEvent(async (client, generation_0, options) => {
119
+ const listPromise = client.listTools();
120
+ const list_0 = options?.startedAt === void 0 ? await listPromise : await withConnectionTimeout(listPromise, "listing tools", options.startedAt);
121
+ if (!isCurrentConnection(generation_0)) return false;
122
+ applyToolsList(list_0);
123
+ return true;
124
+ });
125
+ const finalizeConnect = useEffectEvent(async (transport_2, generation_1) => {
126
+ const clientOptions = {
127
+ ...props.elicitation === false ? {} : { capabilities: { elicitation: {} } },
128
+ listChanged: { tools: {
129
+ autoRefresh: true,
130
+ debounceMs: 300,
131
+ onChanged: (error_0, items) => {
132
+ if (!isCurrentConnection(generation_1)) return;
133
+ if (error_0 !== null) {
134
+ setLastError({ message: error_0.message });
135
+ return;
136
+ }
137
+ if (items === null) return;
138
+ setLastError(null);
139
+ applyToolsList({ tools: items });
140
+ }
141
+ } }
142
+ };
143
+ if (props.cache?.defaultTtlMs !== void 0) clientOptions.defaultCacheTtlMs = props.cache.defaultTtlMs;
144
+ const client_0 = new Client({
145
+ name: "assistant-ui-mcp",
146
+ version: "0.0.0"
147
+ }, clientOptions);
148
+ if (props.elicitation !== false) client_0.setRequestHandler("elicitation/create", (request, context) => {
149
+ if (!isCurrentConnection(generation_1)) return Promise.resolve({ action: "cancel" });
150
+ if (!("requestedSchema" in request.params)) return Promise.resolve({ action: "cancel" });
151
+ const { message, requestedSchema } = request.params;
152
+ const id_2 = typeof crypto !== "undefined" && "randomUUID" in crypto ? crypto.randomUUID() : `mcp-${Date.now()}-${Math.random().toString(36).slice(2)}`;
153
+ const promise_0 = new Promise((resolve) => {
154
+ const onAbort = () => {
155
+ resolvePendingElicitation(id_2, { action: "cancel" });
156
+ };
157
+ elicitationResolversRef.current.set(id_2, {
158
+ resolve,
159
+ signal: context.signal,
160
+ onAbort,
161
+ requestedSchema
162
+ });
163
+ });
164
+ setPendingElicitations((current_1) => [...current_1, {
165
+ id: id_2,
166
+ message,
167
+ requestedSchema
168
+ }]);
169
+ const entry_0 = elicitationResolversRef.current.get(id_2);
170
+ if (entry_0) if (context.signal.aborted) entry_0.onAbort();
171
+ else context.signal.addEventListener("abort", entry_0.onAbort, { once: true });
172
+ return promise_0;
173
+ });
174
+ const startedAt_0 = Date.now();
175
+ await withConnectionTimeout(client_0.connect(transport_2), "connecting", startedAt_0);
176
+ if (!isCurrentConnection(generation_1)) return false;
177
+ if (!await syncTools(client_0, generation_1, { startedAt: startedAt_0 })) return false;
178
+ pendingTransportRef.current = null;
179
+ clientRef.current = client_0;
180
+ transportRef.current = transport_2;
107
181
  setConnectionState("connected");
108
182
  return true;
109
183
  });
110
184
  const doConnect = useEffectEvent(async () => {
111
- const generation_1 = ++connectionGenerationRef.current;
185
+ const generation_2 = ++connectionGenerationRef.current;
112
186
  await closeTransports();
113
- if (!isCurrentConnection(generation_1)) return;
187
+ if (!isCurrentConnection(generation_2)) return;
114
188
  setConnectionState("connecting");
115
189
  setLastError(null);
116
190
  setAuthorizationUrl(null);
@@ -118,19 +192,20 @@ const useMcpServerResource = (props) => {
118
192
  let transport_3 = null;
119
193
  try {
120
194
  transport_3 = await buildTransport();
121
- if (!isCurrentConnection(generation_1)) {
195
+ if (!isCurrentConnection(generation_2)) {
122
196
  await closeQueuedTransports([transport_3]);
123
197
  return;
124
198
  }
125
199
  pendingTransportRef.current = transport_3;
126
- await finalizeConnect(transport_3, generation_1);
200
+ await finalizeConnect(transport_3, generation_2);
127
201
  } catch (err) {
128
- if (!isCurrentConnection(generation_1)) return;
202
+ if (!isCurrentConnection(generation_2)) return;
129
203
  if (err instanceof UnauthorizedError) {
130
204
  pendingTransportRef.current = null;
131
205
  transportRef.current = transport_3;
132
206
  setConnectionState("authRequired");
133
207
  } else {
208
+ cancelPendingElicitations();
134
209
  if (transport_3) {
135
210
  pendingTransportRef.current = null;
136
211
  await closeQueuedTransports([transport_3]);
@@ -148,9 +223,10 @@ const useMcpServerResource = (props) => {
148
223
  await closeTransports();
149
224
  });
150
225
  const doCompleteAuth = useEffectEvent(async (callbackUrl) => {
151
- const generation_2 = ++connectionGenerationRef.current;
226
+ const generation_3 = ++connectionGenerationRef.current;
227
+ cancelPendingElicitations();
152
228
  await closePendingTransport();
153
- if (!isCurrentConnection(generation_2)) throw createInterruptedAuthError();
229
+ if (!isCurrentConnection(generation_3)) throw createInterruptedAuthError();
154
230
  setConnectionState("authPending");
155
231
  setLastError(null);
156
232
  try {
@@ -159,7 +235,7 @@ const useMcpServerResource = (props) => {
159
235
  let transport_4 = transportRef.current;
160
236
  if (!transport_4) {
161
237
  transport_4 = await buildTransport();
162
- if (!isCurrentConnection(generation_2)) {
238
+ if (!isCurrentConnection(generation_3)) {
163
239
  await closeQueuedTransports([transport_4]);
164
240
  throw createInterruptedAuthError();
165
241
  }
@@ -168,16 +244,16 @@ const useMcpServerResource = (props) => {
168
244
  clientRef.current = null;
169
245
  pendingTransportRef.current = transport_4;
170
246
  await transport_4.finishAuth(code);
171
- if (!isCurrentConnection(generation_2)) throw createInterruptedAuthError();
247
+ if (!isCurrentConnection(generation_3)) throw createInterruptedAuthError();
172
248
  setAuthorizationUrl(null);
173
- if (!await finalizeConnect(transport_4, generation_2)) throw createInterruptedAuthError();
249
+ if (!await finalizeConnect(transport_4, generation_3)) throw createInterruptedAuthError();
174
250
  } catch (err_0) {
175
- const error = err_0 instanceof Error ? err_0 : new Error(String(err_0));
176
- if (!isCurrentConnection(generation_2)) throw createInterruptedAuthError(error);
251
+ const error_1 = err_0 instanceof Error ? err_0 : new Error(String(err_0));
252
+ if (!isCurrentConnection(generation_3)) throw createInterruptedAuthError(error_1);
177
253
  await closeTransports();
178
- setLastError({ message: error.message });
254
+ setLastError({ message: error_1.message });
179
255
  setConnectionState("error");
180
- throw error;
256
+ throw error_1;
181
257
  }
182
258
  });
183
259
  const tryAutoConnect = useEffectEvent(async (signal) => {
@@ -224,7 +300,8 @@ const useMcpServerResource = (props) => {
224
300
  connectionState,
225
301
  lastError,
226
302
  tools,
227
- authorizationUrl
303
+ authorizationUrl,
304
+ pendingElicitations
228
305
  }), [
229
306
  props.id,
230
307
  props.kind,
@@ -234,7 +311,8 @@ const useMcpServerResource = (props) => {
234
311
  connectionState,
235
312
  lastError,
236
313
  tools,
237
- authorizationUrl
314
+ authorizationUrl,
315
+ pendingElicitations
238
316
  ]);
239
317
  return {
240
318
  getState: () => state,
@@ -246,24 +324,57 @@ const useMcpServerResource = (props) => {
246
324
  await props.onRemove();
247
325
  },
248
326
  callTool: async (name, args) => {
249
- const client_0 = clientRef.current;
250
- if (!client_0) throw new Error(`MCP server "${props.id}" is not connected`);
251
- return await client_0.callTool({
327
+ const client_1 = clientRef.current;
328
+ if (!client_1) throw new Error(`MCP server "${props.id}" is not connected`);
329
+ return await client_1.callTool({
252
330
  name,
253
331
  arguments: args
254
332
  });
255
333
  },
256
334
  listResources: async (params) => {
257
- const client_1 = clientRef.current;
258
- if (!client_1) throw new Error(`MCP server "${props.id}" is not connected`);
259
- return await client_1.listResources(params);
260
- },
261
- readResource: async (uri) => {
262
335
  const client_2 = clientRef.current;
263
336
  if (!client_2) throw new Error(`MCP server "${props.id}" is not connected`);
264
- return await client_2.readResource({ uri });
337
+ return await client_2.listResources(params);
338
+ },
339
+ readResource: async (uri) => {
340
+ const client_3 = clientRef.current;
341
+ if (!client_3) throw new Error(`MCP server "${props.id}" is not connected`);
342
+ return await client_3.readResource({ uri });
265
343
  },
266
- completeAuth: doCompleteAuth
344
+ completeAuth: doCompleteAuth,
345
+ answerElicitation: (id_3, response) => {
346
+ if (response.action === "accept") {
347
+ const entry_1 = elicitationResolversRef.current.get(id_3);
348
+ if (!entry_1) return;
349
+ if (typeof response.content !== "object" || response.content === null || Array.isArray(response.content)) {
350
+ const errors = [{
351
+ property: "content",
352
+ message: "Response content must be an object."
353
+ }];
354
+ setPendingElicitationError(id_3, {
355
+ message: "Invalid elicitation content: content.",
356
+ properties: ["content"]
357
+ });
358
+ return errors;
359
+ }
360
+ const errors_0 = validateElicitationContent(entry_1.requestedSchema, response.content);
361
+ if (errors_0.length > 0) {
362
+ const properties = [...new Set(errors_0.map((error_2) => error_2.property))];
363
+ setPendingElicitationError(id_3, {
364
+ message: `Invalid elicitation content: ${properties.join(", ")}.`,
365
+ properties
366
+ });
367
+ return errors_0;
368
+ }
369
+ const result_0 = {
370
+ action: "accept",
371
+ content: response.content
372
+ };
373
+ resolvePendingElicitation(id_3, result_0);
374
+ return;
375
+ }
376
+ resolvePendingElicitation(id_3, { action: response.action });
377
+ }
267
378
  };
268
379
  };
269
380
  const McpServerResource = resource(useMcpServerResource);
@@ -1 +1 @@
1
- {"version":3,"file":"McpServerResource.js","names":["useState","useRef","useEffect","useMemo","useEffectEvent","resource","ClientOutput","Client","StreamableHTTPClientTransport","StreamableHTTPClientTransportOptions","UnauthorizedError","Transport","createOAuthProvider","buildHeaders","assertValidServerId","MCPStorage","MCPAuthConfig","MCPConnectionState","MCPServerKind","MCPServerState","MCPToolInfo","McpServerResourceProps","id","kind","name","url","icon","auth","storage","redirectUri","autoConnect","connectionTimeout","onRemove","Promise","useMcpServerResource","props","connectionState","setConnectionState","tools","setTools","lastError","setLastError","message","authorizationUrl","setAuthorizationUrl","clientRef","transportRef","pendingTransportRef","transportCloseQueueRef","resolve","connectionGenerationRef","pendingDisposalRef","cancelled","mountedRef","closeTransportSafely","transport","close","closeQueuedTransports","transports","task","current","then","all","map","closePendingTransport","closeTransports","pendingTransport","activeTransport","Set","filter","isCurrentConnection","generation","createInterruptedAuthError","cause","Error","undefined","withConnectionTimeout","promise","T","phase","startedAt","timeoutMs","remainingMs","Date","now","timeoutError","timeout","ReturnType","setTimeout","race","_","reject","clearTimeout","buildTransport","type","authProvider","serverId","config","onAuthorizationUrl","toString","URL","persisted","loadAuthState","headers","transportOpts","requestInit","finalizeConnect","client","version","connect","list","listTools","t","info","inputSchema","description","doConnect","err","String","doDisconnect","doCompleteAuth","callbackUrl","code","searchParams","get","finishAuth","connected","error","tryAutoConnect","signal","token","tokens","previousDisposal","pendingDisposal","queueMicrotask","state","getState","disconnect","remove","clearAuthState","callTool","args","arguments","Record","listResources","params","readResource","uri","completeAuth","McpServerResource"],"sources":["../../src/resources/McpServerResource.ts"],"sourcesContent":["import { useState, useRef, useEffect, useMemo, useEffectEvent } from \"react\";\nimport { resource } from \"@assistant-ui/tap\";\nimport type { ClientOutput } from \"@assistant-ui/store\";\nimport { Client } from \"@modelcontextprotocol/sdk/client/index.js\";\nimport {\n StreamableHTTPClientTransport,\n type StreamableHTTPClientTransportOptions,\n} from \"@modelcontextprotocol/sdk/client/streamableHttp.js\";\nimport { UnauthorizedError } from \"@modelcontextprotocol/sdk/client/auth.js\";\nimport type { Transport } from \"@modelcontextprotocol/sdk/shared/transport.js\";\nimport { createOAuthProvider } from \"../auth/createOAuthProvider\";\nimport { buildHeaders } from \"../auth/buildHeaders\";\nimport { assertValidServerId } from \"../utils/serverId\";\nimport type { MCPStorage } from \"./storage/types\";\nimport type {\n MCPAuthConfig,\n MCPConnectionState,\n MCPServerKind,\n MCPServerState,\n MCPToolInfo,\n} from \"../mcp-scope\";\n\nexport type McpServerResourceProps = {\n id: string;\n kind: MCPServerKind;\n name: string;\n url: string;\n icon?: string | undefined;\n auth: MCPAuthConfig;\n storage: MCPStorage;\n redirectUri: string;\n autoConnect: boolean;\n connectionTimeout?: number | undefined;\n onRemove: () => Promise<void>;\n};\n\nconst useMcpServerResource = (\n props: McpServerResourceProps,\n): ClientOutput<\"mcpServer\"> => {\n assertValidServerId(props.id);\n const [connectionState, setConnectionState] =\n useState<MCPConnectionState>(\"disconnected\");\n const [tools, setTools] = useState<MCPToolInfo[]>([]);\n const [lastError, setLastError] = useState<{ message: string } | null>(null);\n const [authorizationUrl, setAuthorizationUrl] = useState<string | null>(null);\n\n const clientRef = useRef<Client | null>(null);\n const transportRef = useRef<StreamableHTTPClientTransport | null>(null);\n const pendingTransportRef = useRef<StreamableHTTPClientTransport | null>(\n null,\n );\n const transportCloseQueueRef = useRef(Promise.resolve());\n const connectionGenerationRef = useRef(0);\n const pendingDisposalRef = useRef<{ cancelled: boolean } | null>(null);\n const mountedRef = useRef(true);\n\n const closeTransportSafely = async (\n transport: StreamableHTTPClientTransport,\n ): Promise<void> => {\n try {\n await transport.close();\n } catch {\n // ignore close errors\n }\n };\n\n const closeQueuedTransports = (\n transports: StreamableHTTPClientTransport[],\n ): Promise<void> => {\n const task = transportCloseQueueRef.current.then(async () => {\n await Promise.all(transports.map(closeTransportSafely));\n });\n transportCloseQueueRef.current = task;\n return task;\n };\n\n const closePendingTransport = async () => {\n const transport = pendingTransportRef.current;\n pendingTransportRef.current = null;\n await closeQueuedTransports(transport ? [transport] : []);\n };\n\n const closeTransports = async () => {\n const pendingTransport = pendingTransportRef.current;\n const activeTransport = transportRef.current;\n pendingTransportRef.current = null;\n transportRef.current = null;\n clientRef.current = null;\n\n const transports = new Set(\n [pendingTransport, activeTransport].filter(\n (transport): transport is StreamableHTTPClientTransport =>\n transport !== null,\n ),\n );\n await closeQueuedTransports([...transports]);\n };\n\n const isCurrentConnection = (generation: number) =>\n mountedRef.current && generation === connectionGenerationRef.current;\n\n const createInterruptedAuthError = (cause?: unknown) =>\n new Error(\n `MCP server \"${props.id}\" authorization was interrupted before completion.`,\n cause === undefined ? undefined : { cause },\n );\n\n const withConnectionTimeout = useEffectEvent(\n async <T>(\n promise: Promise<T>,\n phase: \"connecting\" | \"listing tools\",\n startedAt: number,\n ): Promise<T> => {\n const timeoutMs = props.connectionTimeout;\n if (timeoutMs === undefined) return await promise;\n const remainingMs = timeoutMs - (Date.now() - startedAt);\n const timeoutError = () =>\n new Error(\n `MCP server \"${props.id}\" timed out while ${phase} after ${timeoutMs}ms.`,\n );\n if (remainingMs <= 0) throw timeoutError();\n\n let timeout: ReturnType<typeof setTimeout> | undefined;\n try {\n return await Promise.race([\n promise,\n new Promise<never>((_, reject) => {\n timeout = setTimeout(() => reject(timeoutError()), remainingMs);\n }),\n ]);\n } finally {\n if (timeout !== undefined) clearTimeout(timeout);\n }\n },\n );\n\n const buildTransport = useEffectEvent(\n async (): Promise<StreamableHTTPClientTransport> => {\n if (props.auth.type === \"oauth\") {\n const authProvider = createOAuthProvider({\n serverId: props.id,\n config: props.auth,\n storage: props.storage,\n redirectUri: props.redirectUri,\n onAuthorizationUrl: (url) => setAuthorizationUrl(url.toString()),\n });\n return new StreamableHTTPClientTransport(new URL(props.url), {\n authProvider,\n });\n }\n if (props.auth.type === \"bearer\") {\n const persisted = await props.storage.loadAuthState(props.id);\n const headers = buildHeaders(props.auth, persisted);\n const transportOpts: StreamableHTTPClientTransportOptions = {};\n if (headers) transportOpts.requestInit = { headers };\n return new StreamableHTTPClientTransport(\n new URL(props.url),\n transportOpts,\n );\n }\n return new StreamableHTTPClientTransport(new URL(props.url));\n },\n );\n\n const finalizeConnect = useEffectEvent(\n async (\n transport: StreamableHTTPClientTransport,\n generation: number,\n ): Promise<boolean> => {\n const client = new Client({\n name: \"assistant-ui-mcp\",\n version: \"0.0.0\",\n });\n const startedAt = Date.now();\n // SDK's StreamableHTTPClientTransport.sessionId is `string | undefined`\n // but Transport.sessionId is declared `string?` — under\n // exactOptionalPropertyTypes the SDK's own classes don't satisfy its\n // Transport interface. Cast to bridge the gap.\n await withConnectionTimeout(\n client.connect(transport as unknown as Transport),\n \"connecting\",\n startedAt,\n );\n if (!isCurrentConnection(generation)) return false;\n // Defer ref assignment until listTools() also succeeds — otherwise a\n // post-connect failure leaves stale refs that `callTool()` would\n // happily walk into, producing confusing SDK errors instead of\n // \"not connected\".\n const list = await withConnectionTimeout(\n client.listTools(),\n \"listing tools\",\n startedAt,\n );\n if (!isCurrentConnection(generation)) return false;\n\n pendingTransportRef.current = null;\n clientRef.current = client;\n transportRef.current = transport;\n setTools(\n list.tools.map((t) => {\n const info: MCPToolInfo = {\n name: t.name,\n inputSchema: t.inputSchema,\n };\n if (t.description !== undefined) info.description = t.description;\n return info;\n }),\n );\n setConnectionState(\"connected\");\n return true;\n },\n );\n\n const doConnect = useEffectEvent(async () => {\n const generation = ++connectionGenerationRef.current;\n // Close any prior transport/client so a re-connect doesn't leak.\n await closeTransports();\n if (!isCurrentConnection(generation)) return;\n\n setConnectionState(\"connecting\");\n setLastError(null);\n setAuthorizationUrl(null);\n // Clear tools so a reconnect (error → connect, or authRequired\n // → connect) doesn't expose the previous attempt's tool list.\n setTools([]);\n let transport: StreamableHTTPClientTransport | null = null;\n try {\n transport = await buildTransport();\n if (!isCurrentConnection(generation)) {\n await closeQueuedTransports([transport]);\n return;\n }\n pendingTransportRef.current = transport;\n // Don't assign to transportRef until connect succeeds — otherwise a\n // failed `listTools()` leaves an orphaned transport that future\n // doConnect / doDisconnect calls treat as live.\n await finalizeConnect(transport, generation);\n } catch (err) {\n if (!isCurrentConnection(generation)) return;\n\n if (err instanceof UnauthorizedError) {\n // OAuth: keep the transport alive so completeAuth can call\n // finishAuth on it. Closing it before storing would leave a\n // closed transport on transportRef.\n pendingTransportRef.current = null;\n transportRef.current = transport;\n setConnectionState(\"authRequired\");\n } else {\n if (transport) {\n pendingTransportRef.current = null;\n await closeQueuedTransports([transport]);\n }\n setLastError({\n message: err instanceof Error ? err.message : String(err),\n });\n setConnectionState(\"error\");\n }\n }\n });\n\n const doDisconnect = useEffectEvent(async () => {\n connectionGenerationRef.current += 1;\n setTools([]);\n setAuthorizationUrl(null);\n setConnectionState(\"disconnected\");\n await closeTransports();\n });\n\n const doCompleteAuth = useEffectEvent(async (callbackUrl: string) => {\n const generation = ++connectionGenerationRef.current;\n await closePendingTransport();\n if (!isCurrentConnection(generation)) throw createInterruptedAuthError();\n\n setConnectionState(\"authPending\");\n setLastError(null);\n try {\n const url = new URL(callbackUrl);\n const code = url.searchParams.get(\"code\");\n if (!code) throw new Error(\"missing authorization code in callback URL\");\n let transport = transportRef.current;\n if (!transport) {\n transport = await buildTransport();\n if (!isCurrentConnection(generation)) {\n await closeQueuedTransports([transport]);\n throw createInterruptedAuthError();\n }\n }\n transportRef.current = null;\n clientRef.current = null;\n pendingTransportRef.current = transport;\n await transport.finishAuth(code);\n if (!isCurrentConnection(generation)) throw createInterruptedAuthError();\n setAuthorizationUrl(null);\n const connected = await finalizeConnect(transport, generation);\n if (!connected) throw createInterruptedAuthError();\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n if (!isCurrentConnection(generation))\n throw createInterruptedAuthError(error);\n\n await closeTransports();\n setLastError({\n message: error.message,\n });\n setConnectionState(\"error\");\n throw error;\n }\n });\n\n const tryAutoConnect = useEffectEvent(\n async (signal: { cancelled: boolean }) => {\n if (!props.autoConnect) return;\n if (props.auth.type === \"none\") {\n void doConnect();\n return;\n }\n // Static connector token short-circuits the storage read.\n if (props.auth.type === \"bearer\" && props.auth.token) {\n void doConnect();\n return;\n }\n const persisted = await props.storage.loadAuthState(props.id);\n if (signal.cancelled) return;\n if (props.auth.type === \"oauth\") {\n if (!persisted?.tokens) return;\n } else if (!persisted?.token) {\n return;\n }\n void doConnect();\n },\n );\n\n // Auto-connect on mount when usable auth exists.\n useEffect(() => {\n const previousDisposal = pendingDisposalRef.current;\n if (previousDisposal) previousDisposal.cancelled = true;\n const pendingDisposal = { cancelled: false };\n pendingDisposalRef.current = pendingDisposal;\n mountedRef.current = true;\n const signal = { cancelled: false };\n void tryAutoConnect(signal);\n return () => {\n mountedRef.current = false;\n signal.cancelled = true;\n // Defer disposal so StrictMode can replay setup before closing the transport.\n queueMicrotask(() => {\n if (pendingDisposal.cancelled) return;\n connectionGenerationRef.current += 1;\n void closeTransports();\n });\n };\n }, []);\n\n const state = useMemo<MCPServerState>(\n () => ({\n id: props.id,\n kind: props.kind,\n name: props.name,\n url: props.url,\n icon: props.icon,\n connectionState,\n lastError,\n tools,\n authorizationUrl,\n }),\n [\n props.id,\n props.kind,\n props.name,\n props.url,\n props.icon,\n connectionState,\n lastError,\n tools,\n authorizationUrl,\n ],\n );\n\n return {\n getState: () => state,\n connect: doConnect,\n disconnect: doDisconnect,\n remove: async () => {\n await doDisconnect();\n await props.storage.clearAuthState(props.id);\n await props.onRemove();\n },\n callTool: async (name, args) => {\n const client = clientRef.current;\n if (!client) {\n throw new Error(`MCP server \"${props.id}\" is not connected`);\n }\n return await client.callTool({\n name,\n arguments: args as Record<string, unknown> | undefined,\n });\n },\n listResources: async (params) => {\n const client = clientRef.current;\n if (!client) {\n throw new Error(`MCP server \"${props.id}\" is not connected`);\n }\n return await client.listResources(params);\n },\n readResource: async (uri) => {\n const client = clientRef.current;\n if (!client) {\n throw new Error(`MCP server \"${props.id}\" is not connected`);\n }\n return await client.readResource({ uri });\n },\n completeAuth: doCompleteAuth,\n };\n};\n\nexport const McpServerResource = resource(useMcpServerResource);\n"],"mappings":"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"}
1
+ {"version":3,"file":"McpServerResource.js","names":["useState","useRef","useEffect","useMemo","useEffectEvent","resource","ClientOutput","Client","StreamableHTTPClientTransport","UnauthorizedError","ClientOptions","ElicitRequest","ElicitResult","StreamableHTTPClientTransportOptions","createOAuthProvider","buildHeaders","assertValidServerId","validateElicitationContent","MCPStorage","MCPAuthConfig","MCPConnectionState","MCPElicitation","MCPElicitationResponse","MCPServerKind","MCPServerState","MCPToolInfo","McpServerResourceProps","id","kind","name","url","icon","auth","storage","redirectUri","autoConnect","connectionTimeout","cache","defaultTtlMs","elicitation","onRemove","Promise","useMcpServerResource","props","connectionState","setConnectionState","tools","setTools","lastError","setLastError","message","authorizationUrl","setAuthorizationUrl","pendingElicitations","setPendingElicitations","clientRef","transportRef","pendingTransportRef","transportCloseQueueRef","resolve","connectionGenerationRef","elicitationResolversRef","Map","result","signal","AbortSignal","onAbort","requestedSchema","pendingDisposalRef","cancelled","mountedRef","closeTransportSafely","transport","close","closeQueuedTransports","transports","task","current","then","all","map","closePendingTransport","resolvePendingElicitation","entry","get","delete","removeEventListener","filter","setPendingElicitationError","error","NonNullable","has","cancelPendingElicitations","action","closeTransports","pendingTransport","activeTransport","Set","isCurrentConnection","generation","createInterruptedAuthError","cause","Error","undefined","withConnectionTimeout","promise","T","phase","startedAt","timeoutMs","remainingMs","Date","now","timeoutError","timeout","ReturnType","setTimeout","race","_","reject","clearTimeout","buildTransport","type","authProvider","serverId","config","onAuthorizationUrl","toString","URL","persisted","loadAuthState","headers","transportOpts","requestInit","applyToolsList","list","Array","description","inputSchema","t","info","syncTools","client","options","listPromise","listTools","finalizeConnect","clientOptions","capabilities","listChanged","autoRefresh","debounceMs","onChanged","items","defaultCacheTtlMs","version","setRequestHandler","request","context","params","crypto","randomUUID","Math","random","slice","set","aborted","addEventListener","once","connect","synced","doConnect","err","String","doDisconnect","doCompleteAuth","callbackUrl","code","searchParams","finishAuth","connected","tryAutoConnect","token","tokens","previousDisposal","pendingDisposal","queueMicrotask","state","getState","disconnect","remove","clearAuthState","callTool","args","arguments","Record","listResources","readResource","uri","completeAuth","answerElicitation","response","property","content","isArray","errors","properties","length","join","McpServerResource"],"sources":["../../src/resources/McpServerResource.ts"],"sourcesContent":["import { useState, useRef, useEffect, useMemo, useEffectEvent } from \"react\";\nimport { resource } from \"@assistant-ui/tap\";\nimport type { ClientOutput } from \"@assistant-ui/store\";\nimport {\n Client,\n StreamableHTTPClientTransport,\n UnauthorizedError,\n type ClientOptions,\n type ElicitRequest,\n type ElicitResult,\n type StreamableHTTPClientTransportOptions,\n} from \"@modelcontextprotocol/client\";\nimport { createOAuthProvider } from \"../auth/createOAuthProvider\";\nimport { buildHeaders } from \"../auth/buildHeaders\";\nimport { assertValidServerId } from \"../utils/serverId\";\nimport { validateElicitationContent } from \"./validateElicitationContent\";\nimport type { MCPStorage } from \"./storage/types\";\nimport type {\n MCPAuthConfig,\n MCPConnectionState,\n MCPElicitation,\n MCPElicitationResponse,\n MCPServerKind,\n MCPServerState,\n MCPToolInfo,\n} from \"../mcp-scope\";\n\nexport type McpServerResourceProps = {\n id: string;\n kind: MCPServerKind;\n name: string;\n url: string;\n icon?: string | undefined;\n auth: MCPAuthConfig;\n storage: MCPStorage;\n redirectUri: string;\n autoConnect: boolean;\n connectionTimeout?: number | undefined;\n cache?: { readonly defaultTtlMs?: number } | undefined;\n readonly elicitation?: boolean;\n onRemove: () => Promise<void>;\n};\n\nconst useMcpServerResource = (\n props: McpServerResourceProps,\n): ClientOutput<\"mcpServer\"> => {\n assertValidServerId(props.id);\n const [connectionState, setConnectionState] =\n useState<MCPConnectionState>(\"disconnected\");\n const [tools, setTools] = useState<MCPToolInfo[]>([]);\n const [lastError, setLastError] = useState<{ message: string } | null>(null);\n const [authorizationUrl, setAuthorizationUrl] = useState<string | null>(null);\n const [pendingElicitations, setPendingElicitations] = useState<\n MCPElicitation[]\n >([]);\n\n const clientRef = useRef<Client | null>(null);\n const transportRef = useRef<StreamableHTTPClientTransport | null>(null);\n const pendingTransportRef = useRef<StreamableHTTPClientTransport | null>(\n null,\n );\n const transportCloseQueueRef = useRef(Promise.resolve());\n const connectionGenerationRef = useRef(0);\n const elicitationResolversRef = useRef(\n new Map<\n string,\n {\n resolve: (result: ElicitResult) => void;\n signal: AbortSignal;\n onAbort: () => void;\n requestedSchema: unknown;\n }\n >(),\n );\n const pendingDisposalRef = useRef<{ cancelled: boolean } | null>(null);\n const mountedRef = useRef(true);\n\n const closeTransportSafely = async (\n transport: StreamableHTTPClientTransport,\n ): Promise<void> => {\n try {\n await transport.close();\n } catch {\n // ignore close errors\n }\n };\n\n const closeQueuedTransports = (\n transports: StreamableHTTPClientTransport[],\n ): Promise<void> => {\n const task = transportCloseQueueRef.current.then(async () => {\n await Promise.all(transports.map(closeTransportSafely));\n });\n transportCloseQueueRef.current = task;\n return task;\n };\n\n const closePendingTransport = async () => {\n const transport = pendingTransportRef.current;\n pendingTransportRef.current = null;\n await closeQueuedTransports(transport ? [transport] : []);\n };\n\n const resolvePendingElicitation = (id: string, result: ElicitResult) => {\n const entry = elicitationResolversRef.current.get(id);\n if (!entry) return false;\n elicitationResolversRef.current.delete(id);\n entry.signal.removeEventListener(\"abort\", entry.onAbort);\n setPendingElicitations((current) =>\n current.filter((elicitation) => elicitation.id !== id),\n );\n entry.resolve(result);\n return true;\n };\n\n const setPendingElicitationError = (\n id: string,\n error: NonNullable<MCPElicitation[\"error\"]>,\n ) => {\n if (!elicitationResolversRef.current.has(id)) return false;\n setPendingElicitations((current) =>\n current.map((elicitation) =>\n elicitation.id === id ? { ...elicitation, error } : elicitation,\n ),\n );\n return true;\n };\n\n const cancelPendingElicitations = () => {\n for (const [id] of elicitationResolversRef.current) {\n resolvePendingElicitation(id, { action: \"cancel\" });\n }\n };\n\n const closeTransports = async () => {\n cancelPendingElicitations();\n const pendingTransport = pendingTransportRef.current;\n const activeTransport = transportRef.current;\n pendingTransportRef.current = null;\n transportRef.current = null;\n clientRef.current = null;\n\n const transports = new Set(\n [pendingTransport, activeTransport].filter(\n (transport): transport is StreamableHTTPClientTransport =>\n transport !== null,\n ),\n );\n await closeQueuedTransports([...transports]);\n };\n\n const isCurrentConnection = (generation: number) =>\n mountedRef.current && generation === connectionGenerationRef.current;\n\n const createInterruptedAuthError = (cause?: unknown) =>\n new Error(\n `MCP server \"${props.id}\" authorization was interrupted before completion.`,\n cause === undefined ? undefined : { cause },\n );\n\n const withConnectionTimeout = useEffectEvent(\n async <T>(\n promise: Promise<T>,\n phase: \"connecting\" | \"listing tools\",\n startedAt: number,\n ): Promise<T> => {\n const timeoutMs = props.connectionTimeout;\n if (timeoutMs === undefined) return await promise;\n const remainingMs = timeoutMs - (Date.now() - startedAt);\n const timeoutError = () =>\n new Error(\n `MCP server \"${props.id}\" timed out while ${phase} after ${timeoutMs}ms.`,\n );\n if (remainingMs <= 0) throw timeoutError();\n\n let timeout: ReturnType<typeof setTimeout> | undefined;\n try {\n return await Promise.race([\n promise,\n new Promise<never>((_, reject) => {\n timeout = setTimeout(() => reject(timeoutError()), remainingMs);\n }),\n ]);\n } finally {\n if (timeout !== undefined) clearTimeout(timeout);\n }\n },\n );\n\n const buildTransport = useEffectEvent(\n async (): Promise<StreamableHTTPClientTransport> => {\n if (props.auth.type === \"oauth\") {\n const authProvider = createOAuthProvider({\n serverId: props.id,\n config: props.auth,\n storage: props.storage,\n redirectUri: props.redirectUri,\n onAuthorizationUrl: (url) => setAuthorizationUrl(url.toString()),\n });\n return new StreamableHTTPClientTransport(new URL(props.url), {\n authProvider,\n });\n }\n if (props.auth.type === \"bearer\") {\n const persisted = await props.storage.loadAuthState(props.id);\n const headers = buildHeaders(props.auth, persisted);\n const transportOpts: StreamableHTTPClientTransportOptions = {};\n if (headers) transportOpts.requestInit = { headers };\n return new StreamableHTTPClientTransport(\n new URL(props.url),\n transportOpts,\n );\n }\n return new StreamableHTTPClientTransport(new URL(props.url));\n },\n );\n\n const applyToolsList = useEffectEvent(\n (list: {\n tools: Array<{\n name: string;\n description?: string | undefined;\n inputSchema: unknown;\n }>;\n }) => {\n setTools(\n list.tools.map((t) => {\n const info: MCPToolInfo = {\n name: t.name,\n inputSchema: t.inputSchema,\n };\n if (t.description !== undefined) info.description = t.description;\n return info;\n }),\n );\n },\n );\n\n const syncTools = useEffectEvent(\n async (\n client: Client,\n generation: number,\n options?: { startedAt?: number | undefined },\n ): Promise<boolean> => {\n const listPromise = client.listTools();\n const list =\n options?.startedAt === undefined\n ? await listPromise\n : await withConnectionTimeout(\n listPromise,\n \"listing tools\",\n options.startedAt,\n );\n if (!isCurrentConnection(generation)) return false;\n applyToolsList(list);\n return true;\n },\n );\n\n const finalizeConnect = useEffectEvent(\n async (\n transport: StreamableHTTPClientTransport,\n generation: number,\n ): Promise<boolean> => {\n const clientOptions: ClientOptions = {\n ...(props.elicitation === false\n ? {}\n : { capabilities: { elicitation: {} } }),\n listChanged: {\n tools: {\n autoRefresh: true,\n debounceMs: 300,\n onChanged: (error, items) => {\n if (!isCurrentConnection(generation)) return;\n if (error !== null) {\n setLastError({ message: error.message });\n return;\n }\n if (items === null) return;\n setLastError(null);\n applyToolsList({ tools: items });\n },\n },\n },\n };\n if (props.cache?.defaultTtlMs !== undefined) {\n clientOptions.defaultCacheTtlMs = props.cache.defaultTtlMs;\n }\n const client = new Client(\n {\n name: \"assistant-ui-mcp\",\n version: \"0.0.0\",\n },\n clientOptions,\n );\n if (props.elicitation !== false) {\n client.setRequestHandler(\n \"elicitation/create\",\n (request: ElicitRequest, context): Promise<ElicitResult> => {\n if (!isCurrentConnection(generation)) {\n return Promise.resolve({ action: \"cancel\" });\n }\n if (!(\"requestedSchema\" in request.params)) {\n return Promise.resolve({ action: \"cancel\" });\n }\n const { message, requestedSchema } = request.params;\n\n const id =\n typeof crypto !== \"undefined\" && \"randomUUID\" in crypto\n ? crypto.randomUUID()\n : `mcp-${Date.now()}-${Math.random().toString(36).slice(2)}`;\n const promise = new Promise<ElicitResult>((resolve) => {\n const onAbort = () => {\n resolvePendingElicitation(id, { action: \"cancel\" });\n };\n elicitationResolversRef.current.set(id, {\n resolve,\n signal: context.signal,\n onAbort,\n requestedSchema,\n });\n });\n setPendingElicitations((current) => [\n ...current,\n {\n id,\n message,\n requestedSchema,\n },\n ]);\n const entry = elicitationResolversRef.current.get(id);\n if (entry) {\n if (context.signal.aborted) {\n entry.onAbort();\n } else {\n context.signal.addEventListener(\"abort\", entry.onAbort, {\n once: true,\n });\n }\n }\n return promise;\n },\n );\n }\n const startedAt = Date.now();\n await withConnectionTimeout(\n client.connect(transport),\n \"connecting\",\n startedAt,\n );\n if (!isCurrentConnection(generation)) return false;\n // Defer ref assignment until listTools() also succeeds — otherwise a\n // post-connect failure leaves stale refs that `callTool()` would\n // happily walk into, producing confusing SDK errors instead of\n // \"not connected\".\n const synced = await syncTools(client, generation, { startedAt });\n if (!synced) return false;\n\n pendingTransportRef.current = null;\n clientRef.current = client;\n transportRef.current = transport;\n setConnectionState(\"connected\");\n return true;\n },\n );\n\n const doConnect = useEffectEvent(async () => {\n const generation = ++connectionGenerationRef.current;\n // Close any prior transport/client so a re-connect doesn't leak.\n await closeTransports();\n if (!isCurrentConnection(generation)) return;\n\n setConnectionState(\"connecting\");\n setLastError(null);\n setAuthorizationUrl(null);\n // Clear tools so a reconnect (error → connect, or authRequired\n // → connect) doesn't expose the previous attempt's tool list.\n setTools([]);\n let transport: StreamableHTTPClientTransport | null = null;\n try {\n transport = await buildTransport();\n if (!isCurrentConnection(generation)) {\n await closeQueuedTransports([transport]);\n return;\n }\n pendingTransportRef.current = transport;\n // Don't assign to transportRef until connect succeeds — otherwise a\n // failed `listTools()` leaves an orphaned transport that future\n // doConnect / doDisconnect calls treat as live.\n await finalizeConnect(transport, generation);\n } catch (err) {\n if (!isCurrentConnection(generation)) return;\n\n if (err instanceof UnauthorizedError) {\n // OAuth: keep the transport alive so completeAuth can call\n // finishAuth on it. Closing it before storing would leave a\n // closed transport on transportRef.\n pendingTransportRef.current = null;\n transportRef.current = transport;\n setConnectionState(\"authRequired\");\n } else {\n cancelPendingElicitations();\n if (transport) {\n pendingTransportRef.current = null;\n await closeQueuedTransports([transport]);\n }\n setLastError({\n message: err instanceof Error ? err.message : String(err),\n });\n setConnectionState(\"error\");\n }\n }\n });\n\n const doDisconnect = useEffectEvent(async () => {\n connectionGenerationRef.current += 1;\n setTools([]);\n setAuthorizationUrl(null);\n setConnectionState(\"disconnected\");\n await closeTransports();\n });\n\n const doCompleteAuth = useEffectEvent(async (callbackUrl: string) => {\n const generation = ++connectionGenerationRef.current;\n cancelPendingElicitations();\n await closePendingTransport();\n if (!isCurrentConnection(generation)) throw createInterruptedAuthError();\n\n setConnectionState(\"authPending\");\n setLastError(null);\n try {\n const url = new URL(callbackUrl);\n const code = url.searchParams.get(\"code\");\n if (!code) throw new Error(\"missing authorization code in callback URL\");\n let transport = transportRef.current;\n if (!transport) {\n transport = await buildTransport();\n if (!isCurrentConnection(generation)) {\n await closeQueuedTransports([transport]);\n throw createInterruptedAuthError();\n }\n }\n transportRef.current = null;\n clientRef.current = null;\n pendingTransportRef.current = transport;\n await transport.finishAuth(code);\n if (!isCurrentConnection(generation)) throw createInterruptedAuthError();\n setAuthorizationUrl(null);\n const connected = await finalizeConnect(transport, generation);\n if (!connected) throw createInterruptedAuthError();\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n if (!isCurrentConnection(generation))\n throw createInterruptedAuthError(error);\n\n await closeTransports();\n setLastError({\n message: error.message,\n });\n setConnectionState(\"error\");\n throw error;\n }\n });\n\n const tryAutoConnect = useEffectEvent(\n async (signal: { cancelled: boolean }) => {\n if (!props.autoConnect) return;\n if (props.auth.type === \"none\") {\n void doConnect();\n return;\n }\n // Static connector token short-circuits the storage read.\n if (props.auth.type === \"bearer\" && props.auth.token) {\n void doConnect();\n return;\n }\n const persisted = await props.storage.loadAuthState(props.id);\n if (signal.cancelled) return;\n if (props.auth.type === \"oauth\") {\n if (!persisted?.tokens) return;\n } else if (!persisted?.token) {\n return;\n }\n void doConnect();\n },\n );\n\n // Auto-connect on mount when usable auth exists.\n useEffect(() => {\n const previousDisposal = pendingDisposalRef.current;\n if (previousDisposal) previousDisposal.cancelled = true;\n const pendingDisposal = { cancelled: false };\n pendingDisposalRef.current = pendingDisposal;\n mountedRef.current = true;\n const signal = { cancelled: false };\n void tryAutoConnect(signal);\n return () => {\n mountedRef.current = false;\n signal.cancelled = true;\n // Defer disposal so StrictMode can replay setup before closing the transport.\n queueMicrotask(() => {\n if (pendingDisposal.cancelled) return;\n connectionGenerationRef.current += 1;\n void closeTransports();\n });\n };\n }, []);\n\n const state = useMemo<MCPServerState>(\n () => ({\n id: props.id,\n kind: props.kind,\n name: props.name,\n url: props.url,\n icon: props.icon,\n connectionState,\n lastError,\n tools,\n authorizationUrl,\n pendingElicitations,\n }),\n [\n props.id,\n props.kind,\n props.name,\n props.url,\n props.icon,\n connectionState,\n lastError,\n tools,\n authorizationUrl,\n pendingElicitations,\n ],\n );\n\n return {\n getState: () => state,\n connect: doConnect,\n disconnect: doDisconnect,\n remove: async () => {\n await doDisconnect();\n await props.storage.clearAuthState(props.id);\n await props.onRemove();\n },\n callTool: async (name, args) => {\n const client = clientRef.current;\n if (!client) {\n throw new Error(`MCP server \"${props.id}\" is not connected`);\n }\n return await client.callTool({\n name,\n arguments: args as Record<string, unknown> | undefined,\n });\n },\n listResources: async (params) => {\n const client = clientRef.current;\n if (!client) {\n throw new Error(`MCP server \"${props.id}\" is not connected`);\n }\n return await client.listResources(params);\n },\n readResource: async (uri) => {\n const client = clientRef.current;\n if (!client) {\n throw new Error(`MCP server \"${props.id}\" is not connected`);\n }\n return await client.readResource({ uri });\n },\n completeAuth: doCompleteAuth,\n answerElicitation: (\n id: string,\n response: MCPElicitationResponse,\n ): readonly { property: string; message: string }[] | undefined => {\n if (response.action === \"accept\") {\n const entry = elicitationResolversRef.current.get(id);\n if (!entry) return;\n\n if (\n typeof response.content !== \"object\" ||\n response.content === null ||\n Array.isArray(response.content)\n ) {\n const errors = [\n {\n property: \"content\",\n message: \"Response content must be an object.\",\n },\n ];\n setPendingElicitationError(id, {\n message: \"Invalid elicitation content: content.\",\n properties: [\"content\"],\n });\n return errors;\n }\n\n const errors = validateElicitationContent(\n entry.requestedSchema,\n response.content,\n );\n if (errors.length > 0) {\n const properties = [\n ...new Set(errors.map((error) => error.property)),\n ];\n setPendingElicitationError(id, {\n message: `Invalid elicitation content: ${properties.join(\", \")}.`,\n properties,\n });\n return errors;\n }\n\n const result: ElicitResult = {\n action: \"accept\",\n content: response.content as ElicitResult[\"content\"],\n };\n resolvePendingElicitation(id, result);\n return;\n }\n\n resolvePendingElicitation(id, { action: response.action });\n },\n };\n};\n\nexport const McpServerResource = resource(useMcpServerResource);\n"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import { assertValidServerId } from "../../utils/serverId.js";
2
2
  import { resource } from "@assistant-ui/tap";
3
- import { OAuthClientInformationFullSchema, OAuthTokensSchema } from "@modelcontextprotocol/sdk/shared/auth.js";
3
+ import { OAuthClientInformationFullSchema, OAuthTokensSchema } from "@modelcontextprotocol/core";
4
4
  //#region src/resources/storage/McpLocalStorage.ts
5
5
  function resolveStorage(opts) {
6
6
  if (opts.storage) return opts.storage;