@assistant-ui/react-mcp 0.0.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 (221) hide show
  1. package/dist/auth/buildHeaders.d.ts +9 -0
  2. package/dist/auth/buildHeaders.d.ts.map +1 -0
  3. package/dist/auth/buildHeaders.js +15 -0
  4. package/dist/auth/buildHeaders.js.map +1 -0
  5. package/dist/auth/createOAuthProvider.d.ts +22 -0
  6. package/dist/auth/createOAuthProvider.d.ts.map +1 -0
  7. package/dist/auth/createOAuthProvider.js +148 -0
  8. package/dist/auth/createOAuthProvider.js.map +1 -0
  9. package/dist/auth/types.d.ts +9 -0
  10. package/dist/auth/types.d.ts.map +1 -0
  11. package/dist/auth/types.js +2 -0
  12. package/dist/auth/types.js.map +1 -0
  13. package/dist/connector.d.ts +3 -0
  14. package/dist/connector.d.ts.map +1 -0
  15. package/dist/connector.js +6 -0
  16. package/dist/connector.js.map +1 -0
  17. package/dist/context/McpConnectorByIndexProvider.d.ts +5 -0
  18. package/dist/context/McpConnectorByIndexProvider.d.ts.map +1 -0
  19. package/dist/context/McpConnectorByIndexProvider.js +13 -0
  20. package/dist/context/McpConnectorByIndexProvider.js.map +1 -0
  21. package/dist/context/McpCustomServerByIndexProvider.d.ts +5 -0
  22. package/dist/context/McpCustomServerByIndexProvider.d.ts.map +1 -0
  23. package/dist/context/McpCustomServerByIndexProvider.js +13 -0
  24. package/dist/context/McpCustomServerByIndexProvider.js.map +1 -0
  25. package/dist/context/McpServerByIdProvider.d.ts +5 -0
  26. package/dist/context/McpServerByIdProvider.d.ts.map +1 -0
  27. package/dist/context/McpServerByIdProvider.js +13 -0
  28. package/dist/context/McpServerByIdProvider.js.map +1 -0
  29. package/dist/hooks/useMcpOAuthCallback.d.ts +17 -0
  30. package/dist/hooks/useMcpOAuthCallback.d.ts.map +1 -0
  31. package/dist/hooks/useMcpOAuthCallback.js +59 -0
  32. package/dist/hooks/useMcpOAuthCallback.js.map +1 -0
  33. package/dist/index.d.ts +18 -0
  34. package/dist/index.d.ts.map +1 -0
  35. package/dist/index.js +26 -0
  36. package/dist/index.js.map +1 -0
  37. package/dist/mcp-scope.d.ts +109 -0
  38. package/dist/mcp-scope.d.ts.map +1 -0
  39. package/dist/mcp-scope.js +2 -0
  40. package/dist/mcp-scope.js.map +1 -0
  41. package/dist/primitives/addForm/McpAddFormAuthFields.d.ts +15 -0
  42. package/dist/primitives/addForm/McpAddFormAuthFields.d.ts.map +1 -0
  43. package/dist/primitives/addForm/McpAddFormAuthFields.js +18 -0
  44. package/dist/primitives/addForm/McpAddFormAuthFields.js.map +1 -0
  45. package/dist/primitives/addForm/McpAddFormAuthSelect.d.ts +8 -0
  46. package/dist/primitives/addForm/McpAddFormAuthSelect.d.ts.map +1 -0
  47. package/dist/primitives/addForm/McpAddFormAuthSelect.js +24 -0
  48. package/dist/primitives/addForm/McpAddFormAuthSelect.js.map +1 -0
  49. package/dist/primitives/addForm/McpAddFormCancel.d.ts +10 -0
  50. package/dist/primitives/addForm/McpAddFormCancel.d.ts.map +1 -0
  51. package/dist/primitives/addForm/McpAddFormCancel.js +15 -0
  52. package/dist/primitives/addForm/McpAddFormCancel.js.map +1 -0
  53. package/dist/primitives/addForm/McpAddFormError.d.ts +10 -0
  54. package/dist/primitives/addForm/McpAddFormError.d.ts.map +1 -0
  55. package/dist/primitives/addForm/McpAddFormError.js +12 -0
  56. package/dist/primitives/addForm/McpAddFormError.js.map +1 -0
  57. package/dist/primitives/addForm/McpAddFormNameField.d.ts +8 -0
  58. package/dist/primitives/addForm/McpAddFormNameField.d.ts.map +1 -0
  59. package/dist/primitives/addForm/McpAddFormNameField.js +10 -0
  60. package/dist/primitives/addForm/McpAddFormNameField.js.map +1 -0
  61. package/dist/primitives/addForm/McpAddFormRoot.d.ts +16 -0
  62. package/dist/primitives/addForm/McpAddFormRoot.d.ts.map +1 -0
  63. package/dist/primitives/addForm/McpAddFormRoot.js +102 -0
  64. package/dist/primitives/addForm/McpAddFormRoot.js.map +1 -0
  65. package/dist/primitives/addForm/McpAddFormSubmit.d.ts +10 -0
  66. package/dist/primitives/addForm/McpAddFormSubmit.d.ts.map +1 -0
  67. package/dist/primitives/addForm/McpAddFormSubmit.js +10 -0
  68. package/dist/primitives/addForm/McpAddFormSubmit.js.map +1 -0
  69. package/dist/primitives/addForm/McpAddFormUrlField.d.ts +8 -0
  70. package/dist/primitives/addForm/McpAddFormUrlField.d.ts.map +1 -0
  71. package/dist/primitives/addForm/McpAddFormUrlField.js +10 -0
  72. package/dist/primitives/addForm/McpAddFormUrlField.js.map +1 -0
  73. package/dist/primitives/addForm/context.d.ts +21 -0
  74. package/dist/primitives/addForm/context.d.ts.map +1 -0
  75. package/dist/primitives/addForm/context.js +10 -0
  76. package/dist/primitives/addForm/context.js.map +1 -0
  77. package/dist/primitives/addForm.d.ts +9 -0
  78. package/dist/primitives/addForm.d.ts.map +1 -0
  79. package/dist/primitives/addForm.js +9 -0
  80. package/dist/primitives/addForm.js.map +1 -0
  81. package/dist/primitives/manager/McpManagerAddCustomTrigger.d.ts +10 -0
  82. package/dist/primitives/manager/McpManagerAddCustomTrigger.d.ts.map +1 -0
  83. package/dist/primitives/manager/McpManagerAddCustomTrigger.js +9 -0
  84. package/dist/primitives/manager/McpManagerAddCustomTrigger.js.map +1 -0
  85. package/dist/primitives/manager/McpManagerConnectors.d.ts +31 -0
  86. package/dist/primitives/manager/McpManagerConnectors.d.ts.map +1 -0
  87. package/dist/primitives/manager/McpManagerConnectors.js +41 -0
  88. package/dist/primitives/manager/McpManagerConnectors.js.map +1 -0
  89. package/dist/primitives/manager/McpManagerCustomServers.d.ts +31 -0
  90. package/dist/primitives/manager/McpManagerCustomServers.d.ts.map +1 -0
  91. package/dist/primitives/manager/McpManagerCustomServers.js +37 -0
  92. package/dist/primitives/manager/McpManagerCustomServers.js.map +1 -0
  93. package/dist/primitives/manager/McpManagerRoot.d.ts +10 -0
  94. package/dist/primitives/manager/McpManagerRoot.d.ts.map +1 -0
  95. package/dist/primitives/manager/McpManagerRoot.js +10 -0
  96. package/dist/primitives/manager/McpManagerRoot.js.map +1 -0
  97. package/dist/primitives/manager.d.ts +5 -0
  98. package/dist/primitives/manager.d.ts.map +1 -0
  99. package/dist/primitives/manager.js +5 -0
  100. package/dist/primitives/manager.js.map +1 -0
  101. package/dist/primitives/server/McpServerConnectButton.d.ts +10 -0
  102. package/dist/primitives/server/McpServerConnectButton.d.ts.map +1 -0
  103. package/dist/primitives/server/McpServerConnectButton.js +20 -0
  104. package/dist/primitives/server/McpServerConnectButton.js.map +1 -0
  105. package/dist/primitives/server/McpServerDisconnectButton.d.ts +10 -0
  106. package/dist/primitives/server/McpServerDisconnectButton.d.ts.map +1 -0
  107. package/dist/primitives/server/McpServerDisconnectButton.js +20 -0
  108. package/dist/primitives/server/McpServerDisconnectButton.js.map +1 -0
  109. package/dist/primitives/server/McpServerError.d.ts +10 -0
  110. package/dist/primitives/server/McpServerError.d.ts.map +1 -0
  111. package/dist/primitives/server/McpServerError.js +12 -0
  112. package/dist/primitives/server/McpServerError.js.map +1 -0
  113. package/dist/primitives/server/McpServerIcon.d.ts +18 -0
  114. package/dist/primitives/server/McpServerIcon.d.ts.map +1 -0
  115. package/dist/primitives/server/McpServerIcon.js +14 -0
  116. package/dist/primitives/server/McpServerIcon.js.map +1 -0
  117. package/dist/primitives/server/McpServerName.d.ts +10 -0
  118. package/dist/primitives/server/McpServerName.d.ts.map +1 -0
  119. package/dist/primitives/server/McpServerName.js +10 -0
  120. package/dist/primitives/server/McpServerName.js.map +1 -0
  121. package/dist/primitives/server/McpServerOAuthLink.d.ts +16 -0
  122. package/dist/primitives/server/McpServerOAuthLink.d.ts.map +1 -0
  123. package/dist/primitives/server/McpServerOAuthLink.js +13 -0
  124. package/dist/primitives/server/McpServerOAuthLink.js.map +1 -0
  125. package/dist/primitives/server/McpServerRemoveButton.d.ts +10 -0
  126. package/dist/primitives/server/McpServerRemoveButton.d.ts.map +1 -0
  127. package/dist/primitives/server/McpServerRemoveButton.js +18 -0
  128. package/dist/primitives/server/McpServerRemoveButton.js.map +1 -0
  129. package/dist/primitives/server/McpServerRoot.d.ts +10 -0
  130. package/dist/primitives/server/McpServerRoot.d.ts.map +1 -0
  131. package/dist/primitives/server/McpServerRoot.js +13 -0
  132. package/dist/primitives/server/McpServerRoot.js.map +1 -0
  133. package/dist/primitives/server/McpServerStatus.d.ts +10 -0
  134. package/dist/primitives/server/McpServerStatus.d.ts.map +1 -0
  135. package/dist/primitives/server/McpServerStatus.js +10 -0
  136. package/dist/primitives/server/McpServerStatus.js.map +1 -0
  137. package/dist/primitives/server/McpServerToolName.d.ts +10 -0
  138. package/dist/primitives/server/McpServerToolName.d.ts.map +1 -0
  139. package/dist/primitives/server/McpServerToolName.js +10 -0
  140. package/dist/primitives/server/McpServerToolName.js.map +1 -0
  141. package/dist/primitives/server/McpServerTools.d.ts +10 -0
  142. package/dist/primitives/server/McpServerTools.d.ts.map +1 -0
  143. package/dist/primitives/server/McpServerTools.js +19 -0
  144. package/dist/primitives/server/McpServerTools.js.map +1 -0
  145. package/dist/primitives/server.d.ts +12 -0
  146. package/dist/primitives/server.d.ts.map +1 -0
  147. package/dist/primitives/server.js +12 -0
  148. package/dist/primitives/server.js.map +1 -0
  149. package/dist/resources/McpManagerResource.d.ts +13 -0
  150. package/dist/resources/McpManagerResource.d.ts.map +1 -0
  151. package/dist/resources/McpManagerResource.js +191 -0
  152. package/dist/resources/McpManagerResource.js.map +1 -0
  153. package/dist/resources/McpServerResource.d.ts +17 -0
  154. package/dist/resources/McpServerResource.d.ts.map +1 -0
  155. package/dist/resources/McpServerResource.js +239 -0
  156. package/dist/resources/McpServerResource.js.map +1 -0
  157. package/dist/resources/storage/McpCustomStorage.d.ts +3 -0
  158. package/dist/resources/storage/McpCustomStorage.d.ts.map +1 -0
  159. package/dist/resources/storage/McpCustomStorage.js +3 -0
  160. package/dist/resources/storage/McpCustomStorage.js.map +1 -0
  161. package/dist/resources/storage/McpLocalStorage.d.ts +9 -0
  162. package/dist/resources/storage/McpLocalStorage.d.ts.map +1 -0
  163. package/dist/resources/storage/McpLocalStorage.js +67 -0
  164. package/dist/resources/storage/McpLocalStorage.js.map +1 -0
  165. package/dist/resources/storage/McpMemoryStorage.d.ts +3 -0
  166. package/dist/resources/storage/McpMemoryStorage.d.ts.map +1 -0
  167. package/dist/resources/storage/McpMemoryStorage.js +19 -0
  168. package/dist/resources/storage/McpMemoryStorage.js.map +1 -0
  169. package/dist/resources/storage/types.d.ts +12 -0
  170. package/dist/resources/storage/types.d.ts.map +1 -0
  171. package/dist/resources/storage/types.js +2 -0
  172. package/dist/resources/storage/types.js.map +1 -0
  173. package/dist/utils/serverId.d.ts +2 -0
  174. package/dist/utils/serverId.d.ts.map +1 -0
  175. package/dist/utils/serverId.js +16 -0
  176. package/dist/utils/serverId.js.map +1 -0
  177. package/package.json +67 -0
  178. package/src/auth/buildHeaders.ts +19 -0
  179. package/src/auth/createOAuthProvider.ts +172 -0
  180. package/src/auth/types.ts +12 -0
  181. package/src/connector.ts +7 -0
  182. package/src/context/McpConnectorByIndexProvider.tsx +16 -0
  183. package/src/context/McpCustomServerByIndexProvider.tsx +16 -0
  184. package/src/context/McpServerByIdProvider.tsx +17 -0
  185. package/src/hooks/useMcpOAuthCallback.tsx +79 -0
  186. package/src/index.ts +68 -0
  187. package/src/mcp-scope.ts +110 -0
  188. package/src/primitives/addForm/McpAddFormAuthFields.tsx +51 -0
  189. package/src/primitives/addForm/McpAddFormAuthSelect.tsx +55 -0
  190. package/src/primitives/addForm/McpAddFormCancel.tsx +33 -0
  191. package/src/primitives/addForm/McpAddFormError.tsx +27 -0
  192. package/src/primitives/addForm/McpAddFormNameField.tsx +34 -0
  193. package/src/primitives/addForm/McpAddFormRoot.tsx +141 -0
  194. package/src/primitives/addForm/McpAddFormSubmit.tsx +30 -0
  195. package/src/primitives/addForm/McpAddFormUrlField.tsx +35 -0
  196. package/src/primitives/addForm/context.tsx +37 -0
  197. package/src/primitives/addForm.ts +8 -0
  198. package/src/primitives/manager/McpManagerAddCustomTrigger.tsx +21 -0
  199. package/src/primitives/manager/McpManagerConnectors.tsx +76 -0
  200. package/src/primitives/manager/McpManagerCustomServers.tsx +72 -0
  201. package/src/primitives/manager/McpManagerRoot.tsx +28 -0
  202. package/src/primitives/manager.ts +4 -0
  203. package/src/primitives/server/McpServerConnectButton.tsx +39 -0
  204. package/src/primitives/server/McpServerDisconnectButton.tsx +38 -0
  205. package/src/primitives/server/McpServerError.tsx +27 -0
  206. package/src/primitives/server/McpServerIcon.tsx +35 -0
  207. package/src/primitives/server/McpServerName.tsx +26 -0
  208. package/src/primitives/server/McpServerOAuthLink.tsx +38 -0
  209. package/src/primitives/server/McpServerRemoveButton.tsx +35 -0
  210. package/src/primitives/server/McpServerRoot.tsx +35 -0
  211. package/src/primitives/server/McpServerStatus.tsx +26 -0
  212. package/src/primitives/server/McpServerToolName.tsx +26 -0
  213. package/src/primitives/server/McpServerTools.tsx +39 -0
  214. package/src/primitives/server.ts +14 -0
  215. package/src/resources/McpManagerResource.ts +253 -0
  216. package/src/resources/McpServerResource.ts +292 -0
  217. package/src/resources/storage/McpCustomStorage.ts +6 -0
  218. package/src/resources/storage/McpLocalStorage.ts +77 -0
  219. package/src/resources/storage/McpMemoryStorage.ts +22 -0
  220. package/src/resources/storage/types.ts +16 -0
  221. package/src/utils/serverId.ts +19 -0
@@ -0,0 +1,55 @@
1
+ import {
2
+ type ComponentPropsWithoutRef,
3
+ type ComponentRef,
4
+ forwardRef,
5
+ } from "react";
6
+ import { Primitive } from "@radix-ui/react-primitive";
7
+ import { useAddForm, type AddFormAuthType } from "./context";
8
+
9
+ const AUTH_TYPES: ReadonlySet<AddFormAuthType> = new Set([
10
+ "none",
11
+ "bearer",
12
+ "oauth",
13
+ ]);
14
+
15
+ function asAuthType(value: string): AddFormAuthType | null {
16
+ return (AUTH_TYPES as ReadonlySet<string>).has(value)
17
+ ? (value as AddFormAuthType)
18
+ : null;
19
+ }
20
+
21
+ export namespace McpAddFormPrimitiveAuthSelect {
22
+ export type Element = ComponentRef<typeof Primitive.select>;
23
+ export type Props = Omit<
24
+ ComponentPropsWithoutRef<typeof Primitive.select>,
25
+ "value" | "onChange"
26
+ >;
27
+ }
28
+
29
+ export const McpAddFormPrimitiveAuthSelect = forwardRef<
30
+ McpAddFormPrimitiveAuthSelect.Element,
31
+ McpAddFormPrimitiveAuthSelect.Props
32
+ >((props, ref) => {
33
+ const { state, setField } = useAddForm();
34
+ return (
35
+ <Primitive.select
36
+ {...props}
37
+ ref={ref}
38
+ value={state.authType}
39
+ onChange={(e) => {
40
+ const next = asAuthType(e.target.value);
41
+ if (next) setField("authType", next);
42
+ }}
43
+ >
44
+ {props.children ?? (
45
+ <>
46
+ <option value="oauth">OAuth</option>
47
+ <option value="bearer">Bearer token</option>
48
+ <option value="none">None</option>
49
+ </>
50
+ )}
51
+ </Primitive.select>
52
+ );
53
+ });
54
+
55
+ McpAddFormPrimitiveAuthSelect.displayName = "McpAddFormPrimitive.AuthSelect";
@@ -0,0 +1,33 @@
1
+ import {
2
+ type ComponentPropsWithoutRef,
3
+ type ComponentRef,
4
+ forwardRef,
5
+ } from "react";
6
+ import { Primitive } from "@radix-ui/react-primitive";
7
+ import { useAddForm } from "./context";
8
+
9
+ export namespace McpAddFormPrimitiveCancel {
10
+ export type Element = ComponentRef<typeof Primitive.button>;
11
+ export type Props = ComponentPropsWithoutRef<typeof Primitive.button>;
12
+ }
13
+
14
+ export const McpAddFormPrimitiveCancel = forwardRef<
15
+ McpAddFormPrimitiveCancel.Element,
16
+ McpAddFormPrimitiveCancel.Props
17
+ >((props, ref) => {
18
+ const { cancel } = useAddForm();
19
+ return (
20
+ <Primitive.button
21
+ {...props}
22
+ type="button"
23
+ ref={ref}
24
+ onClick={(e) => {
25
+ props.onClick?.(e);
26
+ if (e.defaultPrevented) return;
27
+ cancel();
28
+ }}
29
+ />
30
+ );
31
+ });
32
+
33
+ McpAddFormPrimitiveCancel.displayName = "McpAddFormPrimitive.Cancel";
@@ -0,0 +1,27 @@
1
+ import {
2
+ type ComponentPropsWithoutRef,
3
+ type ComponentRef,
4
+ forwardRef,
5
+ } from "react";
6
+ import { Primitive } from "@radix-ui/react-primitive";
7
+ import { useAddForm } from "./context";
8
+
9
+ export namespace McpAddFormPrimitiveError {
10
+ export type Element = ComponentRef<typeof Primitive.div>;
11
+ export type Props = ComponentPropsWithoutRef<typeof Primitive.div>;
12
+ }
13
+
14
+ export const McpAddFormPrimitiveError = forwardRef<
15
+ McpAddFormPrimitiveError.Element,
16
+ McpAddFormPrimitiveError.Props
17
+ >((props, ref) => {
18
+ const { state } = useAddForm();
19
+ if (!state.error) return null;
20
+ return (
21
+ <Primitive.div {...props} ref={ref}>
22
+ {props.children ?? state.error}
23
+ </Primitive.div>
24
+ );
25
+ });
26
+
27
+ McpAddFormPrimitiveError.displayName = "McpAddFormPrimitive.Error";
@@ -0,0 +1,34 @@
1
+ import {
2
+ type ComponentPropsWithoutRef,
3
+ type ComponentRef,
4
+ forwardRef,
5
+ } from "react";
6
+ import { Primitive } from "@radix-ui/react-primitive";
7
+ import { useAddForm } from "./context";
8
+
9
+ export namespace McpAddFormPrimitiveNameField {
10
+ export type Element = ComponentRef<typeof Primitive.input>;
11
+ export type Props = Omit<
12
+ ComponentPropsWithoutRef<typeof Primitive.input>,
13
+ "value" | "onChange" | "type"
14
+ >;
15
+ }
16
+
17
+ export const McpAddFormPrimitiveNameField = forwardRef<
18
+ McpAddFormPrimitiveNameField.Element,
19
+ McpAddFormPrimitiveNameField.Props
20
+ >((props, ref) => {
21
+ const { state, setField } = useAddForm();
22
+ return (
23
+ <Primitive.input
24
+ type="text"
25
+ placeholder="Name"
26
+ {...props}
27
+ ref={ref}
28
+ value={state.name}
29
+ onChange={(e) => setField("name", e.target.value)}
30
+ />
31
+ );
32
+ });
33
+
34
+ McpAddFormPrimitiveNameField.displayName = "McpAddFormPrimitive.NameField";
@@ -0,0 +1,141 @@
1
+ import {
2
+ type ComponentPropsWithoutRef,
3
+ type ComponentRef,
4
+ type FormEventHandler,
5
+ forwardRef,
6
+ useCallback,
7
+ useMemo,
8
+ useState,
9
+ } from "react";
10
+ import { Primitive } from "@radix-ui/react-primitive";
11
+ import { useAui } from "@assistant-ui/store";
12
+ import { AddFormContext, type AddFormState } from "./context";
13
+ import type { MCPAuthConfig } from "../../mcp-scope";
14
+
15
+ const INITIAL: AddFormState = {
16
+ name: "",
17
+ url: "",
18
+ authType: "oauth",
19
+ bearerToken: "",
20
+ scopes: "",
21
+ submitting: false,
22
+ error: null,
23
+ };
24
+
25
+ function validateUrl(raw: string): { url: string } | { error: string } {
26
+ const trimmed = raw.trim();
27
+ if (!trimmed) return { error: "URL is required" };
28
+ let parsed: URL;
29
+ try {
30
+ parsed = new URL(trimmed);
31
+ } catch {
32
+ return { error: "Invalid URL" };
33
+ }
34
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
35
+ return { error: "URL must be http(s)" };
36
+ }
37
+ return { url: trimmed };
38
+ }
39
+
40
+ export namespace McpAddFormPrimitiveRoot {
41
+ export type Element = ComponentRef<typeof Primitive.form>;
42
+ export type Props = Omit<
43
+ ComponentPropsWithoutRef<typeof Primitive.form>,
44
+ "onSubmit"
45
+ > & {
46
+ onSubmitted?: (id: string) => void;
47
+ onCancel?: () => void;
48
+ };
49
+ }
50
+
51
+ export const McpAddFormPrimitiveRoot = forwardRef<
52
+ McpAddFormPrimitiveRoot.Element,
53
+ McpAddFormPrimitiveRoot.Props
54
+ >(({ onSubmitted, onCancel, ...props }, ref) => {
55
+ const aui = useAui();
56
+ const [state, setState] = useState<AddFormState>(INITIAL);
57
+
58
+ const setField = useCallback(
59
+ <K extends keyof AddFormState>(key: K, value: AddFormState[K]) => {
60
+ setState((prev) => ({ ...prev, [key]: value }));
61
+ },
62
+ [],
63
+ );
64
+
65
+ const reset = useCallback(() => setState(INITIAL), []);
66
+
67
+ const buildAuth = useCallback((): MCPAuthConfig => {
68
+ switch (state.authType) {
69
+ case "none":
70
+ return { type: "none" };
71
+ case "bearer":
72
+ return { type: "bearer", token: state.bearerToken || undefined };
73
+ case "oauth": {
74
+ const scopeList = state.scopes
75
+ .split(/[\s,]+/)
76
+ .map((s) => s.trim())
77
+ .filter(Boolean);
78
+ return {
79
+ type: "oauth",
80
+ scopes: scopeList.length > 0 ? scopeList : undefined,
81
+ };
82
+ }
83
+ }
84
+ }, [state.authType, state.bearerToken, state.scopes]);
85
+
86
+ const submit = useCallback(async () => {
87
+ if (state.submitting) return;
88
+ if (!state.name.trim()) {
89
+ setState((p) => ({ ...p, error: "Name is required" }));
90
+ return;
91
+ }
92
+ if (state.authType === "bearer" && !state.bearerToken.trim()) {
93
+ setState((p) => ({ ...p, error: "Bearer token is required" }));
94
+ return;
95
+ }
96
+ const urlResult = validateUrl(state.url);
97
+ if ("error" in urlResult) {
98
+ setState((p) => ({ ...p, error: urlResult.error }));
99
+ return;
100
+ }
101
+ setState((p) => ({ ...p, submitting: true, error: null }));
102
+ try {
103
+ const id = await aui.mcp().addCustomServer({
104
+ name: state.name.trim(),
105
+ url: urlResult.url,
106
+ auth: buildAuth(),
107
+ });
108
+ setState(INITIAL);
109
+ onSubmitted?.(id);
110
+ } catch (err) {
111
+ setState((p) => ({
112
+ ...p,
113
+ submitting: false,
114
+ error: err instanceof Error ? err.message : String(err),
115
+ }));
116
+ }
117
+ }, [aui, buildAuth, onSubmitted, state]);
118
+
119
+ const cancel = useCallback(() => {
120
+ setState(INITIAL);
121
+ onCancel?.();
122
+ }, [onCancel]);
123
+
124
+ const value = useMemo(
125
+ () => ({ state, setField, reset, submit, cancel }),
126
+ [state, setField, reset, submit, cancel],
127
+ );
128
+
129
+ const onFormSubmit: FormEventHandler<HTMLFormElement> = (e) => {
130
+ e.preventDefault();
131
+ void submit();
132
+ };
133
+
134
+ return (
135
+ <AddFormContext.Provider value={value}>
136
+ <Primitive.form {...props} ref={ref} onSubmit={onFormSubmit} />
137
+ </AddFormContext.Provider>
138
+ );
139
+ });
140
+
141
+ McpAddFormPrimitiveRoot.displayName = "McpAddFormPrimitive.Root";
@@ -0,0 +1,30 @@
1
+ import {
2
+ type ComponentPropsWithoutRef,
3
+ type ComponentRef,
4
+ forwardRef,
5
+ } from "react";
6
+ import { Primitive } from "@radix-ui/react-primitive";
7
+ import { useAddForm } from "./context";
8
+
9
+ export namespace McpAddFormPrimitiveSubmit {
10
+ export type Element = ComponentRef<typeof Primitive.button>;
11
+ export type Props = ComponentPropsWithoutRef<typeof Primitive.button>;
12
+ }
13
+
14
+ export const McpAddFormPrimitiveSubmit = forwardRef<
15
+ McpAddFormPrimitiveSubmit.Element,
16
+ McpAddFormPrimitiveSubmit.Props
17
+ >((props, ref) => {
18
+ const { state } = useAddForm();
19
+ return (
20
+ <Primitive.button
21
+ type="submit"
22
+ {...props}
23
+ ref={ref}
24
+ disabled={props.disabled || state.submitting}
25
+ data-submitting={state.submitting || undefined}
26
+ />
27
+ );
28
+ });
29
+
30
+ McpAddFormPrimitiveSubmit.displayName = "McpAddFormPrimitive.Submit";
@@ -0,0 +1,35 @@
1
+ import {
2
+ type ComponentPropsWithoutRef,
3
+ type ComponentRef,
4
+ forwardRef,
5
+ } from "react";
6
+ import { Primitive } from "@radix-ui/react-primitive";
7
+ import { useAddForm } from "./context";
8
+
9
+ export namespace McpAddFormPrimitiveUrlField {
10
+ export type Element = ComponentRef<typeof Primitive.input>;
11
+ export type Props = Omit<
12
+ ComponentPropsWithoutRef<typeof Primitive.input>,
13
+ "value" | "onChange" | "type"
14
+ >;
15
+ }
16
+
17
+ export const McpAddFormPrimitiveUrlField = forwardRef<
18
+ McpAddFormPrimitiveUrlField.Element,
19
+ McpAddFormPrimitiveUrlField.Props
20
+ >((props, ref) => {
21
+ const { state, setField } = useAddForm();
22
+ return (
23
+ <Primitive.input
24
+ type="url"
25
+ inputMode="url"
26
+ placeholder="https://example.com/mcp"
27
+ {...props}
28
+ ref={ref}
29
+ value={state.url}
30
+ onChange={(e) => setField("url", e.target.value)}
31
+ />
32
+ );
33
+ });
34
+
35
+ McpAddFormPrimitiveUrlField.displayName = "McpAddFormPrimitive.UrlField";
@@ -0,0 +1,37 @@
1
+ import { createContext, useContext } from "react";
2
+ import type { MCPAuthConfig } from "../../mcp-scope";
3
+
4
+ export type AddFormAuthType = MCPAuthConfig["type"];
5
+
6
+ export type AddFormState = {
7
+ name: string;
8
+ url: string;
9
+ authType: AddFormAuthType;
10
+ bearerToken: string;
11
+ scopes: string;
12
+ submitting: boolean;
13
+ error: string | null;
14
+ };
15
+
16
+ export type AddFormContextValue = {
17
+ state: AddFormState;
18
+ setField: <K extends keyof AddFormState>(
19
+ key: K,
20
+ value: AddFormState[K],
21
+ ) => void;
22
+ reset: () => void;
23
+ submit: () => Promise<void>;
24
+ cancel: () => void;
25
+ };
26
+
27
+ export const AddFormContext = createContext<AddFormContextValue | null>(null);
28
+
29
+ export const useAddForm = (): AddFormContextValue => {
30
+ const ctx = useContext(AddFormContext);
31
+ if (!ctx) {
32
+ throw new Error(
33
+ "McpAddFormPrimitive.* must be used inside McpAddFormPrimitive.Root",
34
+ );
35
+ }
36
+ return ctx;
37
+ };
@@ -0,0 +1,8 @@
1
+ export { McpAddFormPrimitiveRoot as Root } from "./addForm/McpAddFormRoot";
2
+ export { McpAddFormPrimitiveNameField as NameField } from "./addForm/McpAddFormNameField";
3
+ export { McpAddFormPrimitiveUrlField as UrlField } from "./addForm/McpAddFormUrlField";
4
+ export { McpAddFormPrimitiveAuthSelect as AuthSelect } from "./addForm/McpAddFormAuthSelect";
5
+ export { McpAddFormPrimitiveAuthFields as AuthFields } from "./addForm/McpAddFormAuthFields";
6
+ export { McpAddFormPrimitiveSubmit as Submit } from "./addForm/McpAddFormSubmit";
7
+ export { McpAddFormPrimitiveCancel as Cancel } from "./addForm/McpAddFormCancel";
8
+ export { McpAddFormPrimitiveError as Error } from "./addForm/McpAddFormError";
@@ -0,0 +1,21 @@
1
+ import {
2
+ type ComponentPropsWithoutRef,
3
+ type ComponentRef,
4
+ forwardRef,
5
+ } from "react";
6
+ import { Primitive } from "@radix-ui/react-primitive";
7
+
8
+ export namespace McpManagerPrimitiveAddCustomTrigger {
9
+ export type Element = ComponentRef<typeof Primitive.button>;
10
+ export type Props = ComponentPropsWithoutRef<typeof Primitive.button>;
11
+ }
12
+
13
+ export const McpManagerPrimitiveAddCustomTrigger = forwardRef<
14
+ McpManagerPrimitiveAddCustomTrigger.Element,
15
+ McpManagerPrimitiveAddCustomTrigger.Props
16
+ >((props, ref) => {
17
+ return <Primitive.button {...props} type="button" ref={ref} />;
18
+ });
19
+
20
+ McpManagerPrimitiveAddCustomTrigger.displayName =
21
+ "McpManagerPrimitive.AddCustomTrigger";
@@ -0,0 +1,76 @@
1
+ import { type FC, type ReactNode, memo, useMemo } from "react";
2
+ import { RenderChildrenWithAccessor, useAuiState } from "@assistant-ui/store";
3
+ import { McpConnectorByIndexProvider } from "../../context/McpConnectorByIndexProvider";
4
+ import type { MCPServerState } from "../../mcp-scope";
5
+
6
+ // ASCII Unit Separator — never appears in MCP connector ids (uuids, urls,
7
+ // app-provided strings).
8
+ const SEP = "\x1f";
9
+
10
+ export namespace McpManagerPrimitiveConnectors {
11
+ export type Props = {
12
+ /**
13
+ * Render function called once per connector. Receives a lazy `server`
14
+ * accessor — reading it inside the render function subscribes to that
15
+ * connector's state.
16
+ */
17
+ children: (value: { server: MCPServerState }) => ReactNode;
18
+ };
19
+ }
20
+
21
+ const McpManagerPrimitiveConnectorsInner: FC<{
22
+ children: (value: { server: MCPServerState }) => ReactNode;
23
+ }> = ({ children }) => {
24
+ // Subscribe to the connector id list, joined to a primitive so identity
25
+ // is stable when the list hasn't changed. Re-renders on add/remove/reorder
26
+ // but not on per-item state changes.
27
+ const idsJoined = useAuiState((s) =>
28
+ s.mcp.connectors.map((c) => c.id).join(SEP),
29
+ );
30
+ const ids = useMemo(
31
+ () => (idsJoined ? idsJoined.split(SEP) : []),
32
+ [idsJoined],
33
+ );
34
+
35
+ return useMemo(() => {
36
+ if (ids.length === 0) return null;
37
+ return ids.map((id, index) => (
38
+ <McpConnectorByIndexProvider key={id} index={index}>
39
+ <RenderChildrenWithAccessor
40
+ getItemState={(aui) => aui.mcp().connector({ index }).getState()}
41
+ >
42
+ {(getItem) =>
43
+ children({
44
+ get server() {
45
+ return getItem();
46
+ },
47
+ })
48
+ }
49
+ </RenderChildrenWithAccessor>
50
+ </McpConnectorByIndexProvider>
51
+ ));
52
+ }, [ids, children]);
53
+ };
54
+
55
+ /**
56
+ * Renders all connectors declared on `McpManagerResource`.
57
+ *
58
+ * @example
59
+ * ```tsx
60
+ * <McpManagerPrimitive.Connectors>
61
+ * {({ server }) => (
62
+ * <McpServerPrimitive.Root>
63
+ * <McpServerPrimitive.Name />
64
+ * {server.connectionState === "error" && <p>{server.lastError?.message}</p>}
65
+ * </McpServerPrimitive.Root>
66
+ * )}
67
+ * </McpManagerPrimitive.Connectors>
68
+ * ```
69
+ */
70
+ export const McpManagerPrimitiveConnectors: FC<McpManagerPrimitiveConnectors.Props> =
71
+ memo(
72
+ McpManagerPrimitiveConnectorsInner,
73
+ (prev, next) => prev.children === next.children,
74
+ );
75
+
76
+ McpManagerPrimitiveConnectors.displayName = "McpManagerPrimitive.Connectors";
@@ -0,0 +1,72 @@
1
+ import { type FC, type ReactNode, memo, useMemo } from "react";
2
+ import { RenderChildrenWithAccessor, useAuiState } from "@assistant-ui/store";
3
+ import { McpCustomServerByIndexProvider } from "../../context/McpCustomServerByIndexProvider";
4
+ import type { MCPServerState } from "../../mcp-scope";
5
+
6
+ const SEP = "\x1f";
7
+
8
+ export namespace McpManagerPrimitiveCustomServers {
9
+ export type Props = {
10
+ /**
11
+ * Render function called once per custom server. Receives a lazy
12
+ * `server` accessor — reading it inside the render function subscribes
13
+ * to that server's state.
14
+ */
15
+ children: (value: { server: MCPServerState }) => ReactNode;
16
+ };
17
+ }
18
+
19
+ const McpManagerPrimitiveCustomServersInner: FC<{
20
+ children: (value: { server: MCPServerState }) => ReactNode;
21
+ }> = ({ children }) => {
22
+ const idsJoined = useAuiState((s) =>
23
+ s.mcp.customServers.map((c) => c.id).join(SEP),
24
+ );
25
+ const ids = useMemo(
26
+ () => (idsJoined ? idsJoined.split(SEP) : []),
27
+ [idsJoined],
28
+ );
29
+
30
+ return useMemo(() => {
31
+ if (ids.length === 0) return null;
32
+ return ids.map((id, index) => (
33
+ <McpCustomServerByIndexProvider key={id} index={index}>
34
+ <RenderChildrenWithAccessor
35
+ getItemState={(aui) => aui.mcp().customServer({ index }).getState()}
36
+ >
37
+ {(getItem) =>
38
+ children({
39
+ get server() {
40
+ return getItem();
41
+ },
42
+ })
43
+ }
44
+ </RenderChildrenWithAccessor>
45
+ </McpCustomServerByIndexProvider>
46
+ ));
47
+ }, [ids, children]);
48
+ };
49
+
50
+ /**
51
+ * Renders all user-added custom servers persisted in storage.
52
+ *
53
+ * @example
54
+ * ```tsx
55
+ * <McpManagerPrimitive.CustomServers>
56
+ * {() => (
57
+ * <McpServerPrimitive.Root>
58
+ * <McpServerPrimitive.Name />
59
+ * <McpServerPrimitive.RemoveButton>Remove</McpServerPrimitive.RemoveButton>
60
+ * </McpServerPrimitive.Root>
61
+ * )}
62
+ * </McpManagerPrimitive.CustomServers>
63
+ * ```
64
+ */
65
+ export const McpManagerPrimitiveCustomServers: FC<McpManagerPrimitiveCustomServers.Props> =
66
+ memo(
67
+ McpManagerPrimitiveCustomServersInner,
68
+ (prev, next) => prev.children === next.children,
69
+ );
70
+
71
+ McpManagerPrimitiveCustomServers.displayName =
72
+ "McpManagerPrimitive.CustomServers";
@@ -0,0 +1,28 @@
1
+ import {
2
+ type ComponentPropsWithoutRef,
3
+ type ComponentRef,
4
+ forwardRef,
5
+ } from "react";
6
+ import { Primitive } from "@radix-ui/react-primitive";
7
+ import { useAuiState } from "@assistant-ui/store";
8
+
9
+ export namespace McpManagerPrimitiveRoot {
10
+ export type Element = ComponentRef<typeof Primitive.div>;
11
+ export type Props = ComponentPropsWithoutRef<typeof Primitive.div>;
12
+ }
13
+
14
+ export const McpManagerPrimitiveRoot = forwardRef<
15
+ McpManagerPrimitiveRoot.Element,
16
+ McpManagerPrimitiveRoot.Props
17
+ >((props, ref) => {
18
+ const isHydrated = useAuiState((s) => s.mcp.isHydrated);
19
+ return (
20
+ <Primitive.div
21
+ {...props}
22
+ ref={ref}
23
+ data-mcp-hydrated={isHydrated || undefined}
24
+ />
25
+ );
26
+ });
27
+
28
+ McpManagerPrimitiveRoot.displayName = "McpManagerPrimitive.Root";
@@ -0,0 +1,4 @@
1
+ export { McpManagerPrimitiveRoot as Root } from "./manager/McpManagerRoot";
2
+ export { McpManagerPrimitiveConnectors as Connectors } from "./manager/McpManagerConnectors";
3
+ export { McpManagerPrimitiveCustomServers as CustomServers } from "./manager/McpManagerCustomServers";
4
+ export { McpManagerPrimitiveAddCustomTrigger as AddCustomTrigger } from "./manager/McpManagerAddCustomTrigger";
@@ -0,0 +1,39 @@
1
+ import {
2
+ type ComponentPropsWithoutRef,
3
+ type ComponentRef,
4
+ forwardRef,
5
+ } from "react";
6
+ import { Primitive } from "@radix-ui/react-primitive";
7
+ import { useAui, useAuiState } from "@assistant-ui/store";
8
+
9
+ export namespace McpServerPrimitiveConnectButton {
10
+ export type Element = ComponentRef<typeof Primitive.button>;
11
+ export type Props = ComponentPropsWithoutRef<typeof Primitive.button>;
12
+ }
13
+
14
+ const CONNECTABLE = new Set(["disconnected", "error", "authRequired"]);
15
+
16
+ export const McpServerPrimitiveConnectButton = forwardRef<
17
+ McpServerPrimitiveConnectButton.Element,
18
+ McpServerPrimitiveConnectButton.Props
19
+ >((props, ref) => {
20
+ const state = useAuiState((s) => s.mcpServer.connectionState);
21
+ const aui = useAui();
22
+ if (!CONNECTABLE.has(state)) return null;
23
+ return (
24
+ <Primitive.button
25
+ {...props}
26
+ type="button"
27
+ ref={ref}
28
+ data-state-hint={state === "authRequired" ? "auth-required" : undefined}
29
+ onClick={(e) => {
30
+ props.onClick?.(e);
31
+ if (e.defaultPrevented) return;
32
+ void aui.mcpServer().connect();
33
+ }}
34
+ />
35
+ );
36
+ });
37
+
38
+ McpServerPrimitiveConnectButton.displayName =
39
+ "McpServerPrimitive.ConnectButton";