@assistant-ui/react-mcp 0.0.0 → 0.0.2

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 (179) hide show
  1. package/LICENSE +21 -0
  2. package/dist/_virtual/_rolldown/runtime.js +13 -0
  3. package/dist/auth/buildHeaders.d.ts +7 -3
  4. package/dist/auth/buildHeaders.d.ts.map +1 -1
  5. package/dist/auth/buildHeaders.js +14 -12
  6. package/dist/auth/buildHeaders.js.map +1 -1
  7. package/dist/auth/createOAuthProvider.d.ts +17 -15
  8. package/dist/auth/createOAuthProvider.d.ts.map +1 -1
  9. package/dist/auth/createOAuthProvider.js +111 -137
  10. package/dist/auth/createOAuthProvider.js.map +1 -1
  11. package/dist/auth/types.d.ts +10 -7
  12. package/dist/auth/types.d.ts.map +1 -1
  13. package/dist/auth/types.js +0 -2
  14. package/dist/connector.d.ts +6 -2
  15. package/dist/connector.d.ts.map +1 -1
  16. package/dist/connector.js +7 -3
  17. package/dist/connector.js.map +1 -1
  18. package/dist/context/McpConnectorByIndexProvider.d.ts +7 -3
  19. package/dist/context/McpConnectorByIndexProvider.d.ts.map +1 -1
  20. package/dist/context/McpConnectorByIndexProvider.js +18 -11
  21. package/dist/context/McpConnectorByIndexProvider.js.map +1 -1
  22. package/dist/context/McpCustomServerByIndexProvider.d.ts +7 -3
  23. package/dist/context/McpCustomServerByIndexProvider.d.ts.map +1 -1
  24. package/dist/context/McpCustomServerByIndexProvider.js +18 -11
  25. package/dist/context/McpCustomServerByIndexProvider.js.map +1 -1
  26. package/dist/context/McpServerByIdProvider.d.ts +7 -3
  27. package/dist/context/McpServerByIdProvider.d.ts.map +1 -1
  28. package/dist/context/McpServerByIdProvider.js +15 -11
  29. package/dist/context/McpServerByIdProvider.js.map +1 -1
  30. package/dist/hooks/useMcpOAuthCallback.d.ts +16 -13
  31. package/dist/hooks/useMcpOAuthCallback.d.ts.map +1 -1
  32. package/dist/hooks/useMcpOAuthCallback.js +59 -55
  33. package/dist/hooks/useMcpOAuthCallback.js.map +1 -1
  34. package/dist/index.d.ts +17 -18
  35. package/dist/index.js +14 -26
  36. package/dist/mcp-scope.d.ts +91 -94
  37. package/dist/mcp-scope.d.ts.map +1 -1
  38. package/dist/mcp-scope.js +0 -1
  39. package/dist/primitives/addForm/McpAddFormAuthFields.d.ts +17 -13
  40. package/dist/primitives/addForm/McpAddFormAuthFields.d.ts.map +1 -1
  41. package/dist/primitives/addForm/McpAddFormAuthFields.js +23 -14
  42. package/dist/primitives/addForm/McpAddFormAuthFields.js.map +1 -1
  43. package/dist/primitives/addForm/McpAddFormAuthSelect.d.ts +9 -5
  44. package/dist/primitives/addForm/McpAddFormAuthSelect.d.ts.map +1 -1
  45. package/dist/primitives/addForm/McpAddFormAuthSelect.js +36 -16
  46. package/dist/primitives/addForm/McpAddFormAuthSelect.js.map +1 -1
  47. package/dist/primitives/addForm/McpAddFormCancel.d.ts +10 -6
  48. package/dist/primitives/addForm/McpAddFormCancel.d.ts.map +1 -1
  49. package/dist/primitives/addForm/McpAddFormCancel.js +19 -11
  50. package/dist/primitives/addForm/McpAddFormCancel.js.map +1 -1
  51. package/dist/primitives/addForm/McpAddFormError.d.ts +10 -6
  52. package/dist/primitives/addForm/McpAddFormError.d.ts.map +1 -1
  53. package/dist/primitives/addForm/McpAddFormError.js +15 -8
  54. package/dist/primitives/addForm/McpAddFormError.js.map +1 -1
  55. package/dist/primitives/addForm/McpAddFormNameField.d.ts +9 -5
  56. package/dist/primitives/addForm/McpAddFormNameField.d.ts.map +1 -1
  57. package/dist/primitives/addForm/McpAddFormNameField.js +17 -6
  58. package/dist/primitives/addForm/McpAddFormNameField.js.map +1 -1
  59. package/dist/primitives/addForm/McpAddFormRoot.d.ts +15 -11
  60. package/dist/primitives/addForm/McpAddFormRoot.d.ts.map +1 -1
  61. package/dist/primitives/addForm/McpAddFormRoot.js +134 -94
  62. package/dist/primitives/addForm/McpAddFormRoot.js.map +1 -1
  63. package/dist/primitives/addForm/McpAddFormSubmit.d.ts +10 -6
  64. package/dist/primitives/addForm/McpAddFormSubmit.d.ts.map +1 -1
  65. package/dist/primitives/addForm/McpAddFormSubmit.js +16 -6
  66. package/dist/primitives/addForm/McpAddFormSubmit.js.map +1 -1
  67. package/dist/primitives/addForm/McpAddFormUrlField.d.ts +9 -5
  68. package/dist/primitives/addForm/McpAddFormUrlField.d.ts.map +1 -1
  69. package/dist/primitives/addForm/McpAddFormUrlField.js +18 -6
  70. package/dist/primitives/addForm/McpAddFormUrlField.js.map +1 -1
  71. package/dist/primitives/addForm/context.d.ts +22 -18
  72. package/dist/primitives/addForm/context.d.ts.map +1 -1
  73. package/dist/primitives/addForm/context.js +9 -7
  74. package/dist/primitives/addForm/context.js.map +1 -1
  75. package/dist/primitives/addForm.d.ts +15 -8
  76. package/dist/primitives/addForm.d.ts.map +1 -1
  77. package/dist/primitives/addForm.js +23 -8
  78. package/dist/primitives/addForm.js.map +1 -1
  79. package/dist/primitives/manager/McpManagerAddCustomTrigger.d.ts +10 -6
  80. package/dist/primitives/manager/McpManagerAddCustomTrigger.d.ts.map +1 -1
  81. package/dist/primitives/manager/McpManagerAddCustomTrigger.js +13 -6
  82. package/dist/primitives/manager/McpManagerAddCustomTrigger.js.map +1 -1
  83. package/dist/primitives/manager/McpManagerConnectors.d.ts +18 -14
  84. package/dist/primitives/manager/McpManagerConnectors.d.ts.map +1 -1
  85. package/dist/primitives/manager/McpManagerConnectors.js +37 -35
  86. package/dist/primitives/manager/McpManagerConnectors.js.map +1 -1
  87. package/dist/primitives/manager/McpManagerCustomServers.d.ts +18 -14
  88. package/dist/primitives/manager/McpManagerCustomServers.d.ts.map +1 -1
  89. package/dist/primitives/manager/McpManagerCustomServers.js +38 -32
  90. package/dist/primitives/manager/McpManagerCustomServers.js.map +1 -1
  91. package/dist/primitives/manager/McpManagerRoot.d.ts +10 -6
  92. package/dist/primitives/manager/McpManagerRoot.d.ts.map +1 -1
  93. package/dist/primitives/manager/McpManagerRoot.js +14 -6
  94. package/dist/primitives/manager/McpManagerRoot.js.map +1 -1
  95. package/dist/primitives/manager.d.ts +11 -4
  96. package/dist/primitives/manager.d.ts.map +1 -1
  97. package/dist/primitives/manager.js +15 -4
  98. package/dist/primitives/manager.js.map +1 -1
  99. package/dist/primitives/server/McpServerConnectButton.d.ts +10 -6
  100. package/dist/primitives/server/McpServerConnectButton.d.ts.map +1 -1
  101. package/dist/primitives/server/McpServerConnectButton.js +28 -17
  102. package/dist/primitives/server/McpServerConnectButton.js.map +1 -1
  103. package/dist/primitives/server/McpServerDisconnectButton.d.ts +10 -6
  104. package/dist/primitives/server/McpServerDisconnectButton.d.ts.map +1 -1
  105. package/dist/primitives/server/McpServerDisconnectButton.js +27 -17
  106. package/dist/primitives/server/McpServerDisconnectButton.js.map +1 -1
  107. package/dist/primitives/server/McpServerError.d.ts +10 -6
  108. package/dist/primitives/server/McpServerError.d.ts.map +1 -1
  109. package/dist/primitives/server/McpServerError.js +15 -8
  110. package/dist/primitives/server/McpServerError.js.map +1 -1
  111. package/dist/primitives/server/McpServerIcon.d.ts +16 -14
  112. package/dist/primitives/server/McpServerIcon.d.ts.map +1 -1
  113. package/dist/primitives/server/McpServerIcon.js +18 -10
  114. package/dist/primitives/server/McpServerIcon.js.map +1 -1
  115. package/dist/primitives/server/McpServerName.d.ts +10 -6
  116. package/dist/primitives/server/McpServerName.d.ts.map +1 -1
  117. package/dist/primitives/server/McpServerName.js +14 -6
  118. package/dist/primitives/server/McpServerName.js.map +1 -1
  119. package/dist/primitives/server/McpServerOAuthLink.d.ts +13 -11
  120. package/dist/primitives/server/McpServerOAuthLink.d.ts.map +1 -1
  121. package/dist/primitives/server/McpServerOAuthLink.js +18 -9
  122. package/dist/primitives/server/McpServerOAuthLink.js.map +1 -1
  123. package/dist/primitives/server/McpServerRemoveButton.d.ts +10 -6
  124. package/dist/primitives/server/McpServerRemoveButton.d.ts.map +1 -1
  125. package/dist/primitives/server/McpServerRemoveButton.js +21 -14
  126. package/dist/primitives/server/McpServerRemoveButton.js.map +1 -1
  127. package/dist/primitives/server/McpServerRoot.d.ts +10 -6
  128. package/dist/primitives/server/McpServerRoot.d.ts.map +1 -1
  129. package/dist/primitives/server/McpServerRoot.js +20 -9
  130. package/dist/primitives/server/McpServerRoot.js.map +1 -1
  131. package/dist/primitives/server/McpServerStatus.d.ts +10 -6
  132. package/dist/primitives/server/McpServerStatus.d.ts.map +1 -1
  133. package/dist/primitives/server/McpServerStatus.js +15 -6
  134. package/dist/primitives/server/McpServerStatus.js.map +1 -1
  135. package/dist/primitives/server/McpServerToolName.d.ts +10 -6
  136. package/dist/primitives/server/McpServerToolName.d.ts.map +1 -1
  137. package/dist/primitives/server/McpServerToolName.js +15 -6
  138. package/dist/primitives/server/McpServerToolName.js.map +1 -1
  139. package/dist/primitives/server/McpServerTools.d.ts +12 -8
  140. package/dist/primitives/server/McpServerTools.d.ts.map +1 -1
  141. package/dist/primitives/server/McpServerTools.js +17 -13
  142. package/dist/primitives/server/McpServerTools.js.map +1 -1
  143. package/dist/primitives/server.d.ts +18 -11
  144. package/dist/primitives/server.d.ts.map +1 -1
  145. package/dist/primitives/server.js +30 -11
  146. package/dist/primitives/server.js.map +1 -1
  147. package/dist/resources/McpManagerResource.d.ts +13 -11
  148. package/dist/resources/McpManagerResource.d.ts.map +1 -1
  149. package/dist/resources/McpManagerResource.js +149 -183
  150. package/dist/resources/McpManagerResource.js.map +1 -1
  151. package/dist/resources/McpServerResource.d.ts +19 -15
  152. package/dist/resources/McpServerResource.d.ts.map +1 -1
  153. package/dist/resources/McpServerResource.js +186 -235
  154. package/dist/resources/McpServerResource.js.map +1 -1
  155. package/dist/resources/storage/McpCustomStorage.d.ts +6 -2
  156. package/dist/resources/storage/McpCustomStorage.d.ts.map +1 -1
  157. package/dist/resources/storage/McpCustomStorage.js +5 -1
  158. package/dist/resources/storage/McpCustomStorage.js.map +1 -1
  159. package/dist/resources/storage/McpLocalStorage.d.ts +9 -7
  160. package/dist/resources/storage/McpLocalStorage.d.ts.map +1 -1
  161. package/dist/resources/storage/McpLocalStorage.js +51 -62
  162. package/dist/resources/storage/McpLocalStorage.js.map +1 -1
  163. package/dist/resources/storage/McpMemoryStorage.d.ts +6 -2
  164. package/dist/resources/storage/McpMemoryStorage.d.ts.map +1 -1
  165. package/dist/resources/storage/McpMemoryStorage.js +20 -16
  166. package/dist/resources/storage/McpMemoryStorage.js.map +1 -1
  167. package/dist/resources/storage/types.d.ts +14 -10
  168. package/dist/resources/storage/types.d.ts.map +1 -1
  169. package/dist/resources/storage/types.js +0 -2
  170. package/dist/utils/serverId.d.ts +4 -1
  171. package/dist/utils/serverId.d.ts.map +1 -1
  172. package/dist/utils/serverId.js +8 -14
  173. package/dist/utils/serverId.js.map +1 -1
  174. package/package.json +12 -12
  175. package/dist/auth/types.js.map +0 -1
  176. package/dist/index.d.ts.map +0 -1
  177. package/dist/index.js.map +0 -1
  178. package/dist/mcp-scope.js.map +0 -1
  179. package/dist/resources/storage/types.js.map +0 -1
@@ -1,191 +1,157 @@
1
- import { resource, tapState, tapResource, tapEffect, tapMemo, tapEffectEvent, tapRef, withKey, } from "@assistant-ui/tap";
2
- import { tapClientLookup, tapAssistantClientRef, attachTransformScopes, } from "@assistant-ui/store";
3
- import { ModelContext } from "@assistant-ui/core/store";
4
1
  import { McpServerResource } from "./McpServerResource.js";
5
2
  import { McpLocalStorage } from "./storage/McpLocalStorage.js";
3
+ import { attachTransformScopes, tapAssistantClientRef, tapClientLookup } from "@assistant-ui/store";
4
+ import { resource, tapEffect, tapEffectEvent, tapMemo, tapRef, tapResource, tapState, withKey } from "@assistant-ui/tap";
5
+ import { ModelContext } from "@assistant-ui/core/store";
6
+ //#region src/resources/McpManagerResource.ts
6
7
  function defaultRedirectUri() {
7
- if (typeof window === "undefined")
8
- return "";
9
- return `${window.location.origin}/mcp/callback`;
8
+ if (typeof window === "undefined") return "";
9
+ return `${window.location.origin}/mcp/callback`;
10
10
  }
11
- export const McpManagerResource = resource((props) => {
12
- const connectors = props.connectors ?? [];
13
- const autoConnect = props.autoConnect ?? true;
14
- const redirectUri = props.oauthRedirectUri ?? defaultRedirectUri();
15
- const storageElement = props.storage ?? McpLocalStorage();
16
- const storage = tapResource(storageElement);
17
- const [customServers, setCustomServers] = tapState([]);
18
- const [isHydrated, setIsHydrated] = tapState(false);
19
- const hydratedRef = tapRef(false);
20
- const hydrate = tapEffectEvent(async (signal) => {
21
- try {
22
- const records = await storage.loadCustomServers();
23
- if (signal.cancelled)
24
- return;
25
- // Merge rather than replace so any addCustomServer calls that
26
- // happened before hydration resolved aren't silently overwritten.
27
- // Persisted order wins; pre-hydration locals append.
28
- setCustomServers((prev) => {
29
- if (prev.length === 0)
30
- return records;
31
- const persistedIds = new Set(records.map((r) => r.id));
32
- return [...records, ...prev.filter((r) => !persistedIds.has(r.id))];
33
- });
34
- }
35
- finally {
36
- if (!signal.cancelled) {
37
- hydratedRef.current = true;
38
- setIsHydrated(true);
39
- }
40
- }
41
- });
42
- tapEffect(() => {
43
- const signal = { cancelled: false };
44
- void hydrate(signal);
45
- return () => {
46
- signal.cancelled = true;
47
- };
48
- }, []);
49
- const persistCustomServers = tapEffectEvent(async (records) => {
50
- if (!hydratedRef.current)
51
- return;
52
- await storage.saveCustomServers(records);
53
- });
54
- tapEffect(() => {
55
- void persistCustomServers(customServers);
56
- }, [customServers]);
57
- const serverElements = tapMemo(() => {
58
- const connectorElements = connectors.map((c) => withKey(c.id, McpServerResource({
59
- id: c.id,
60
- kind: "connector",
61
- name: c.name,
62
- url: c.url,
63
- icon: c.icon,
64
- auth: c.auth,
65
- storage,
66
- redirectUri,
67
- autoConnect,
68
- onRemove: async () => {
69
- // connectors cannot be removed
70
- },
71
- })));
72
- const customElements = customServers.map((s) => withKey(s.id, McpServerResource({
73
- id: s.id,
74
- kind: "custom",
75
- name: s.name,
76
- url: s.url,
77
- auth: s.auth,
78
- storage,
79
- redirectUri,
80
- autoConnect,
81
- onRemove: async () => {
82
- setCustomServers((prev) => prev.filter((x) => x.id !== s.id));
83
- },
84
- })));
85
- return [...connectorElements, ...customElements];
86
- }, [connectors, customServers, storage, redirectUri, autoConnect]);
87
- const lookup = tapClientLookup(() => serverElements, [serverElements]);
88
- const state = tapMemo(() => {
89
- const all = lookup.state;
90
- return {
91
- servers: all,
92
- connectors: all.filter((s) => s.kind === "connector"),
93
- customServers: all.filter((s) => s.kind === "custom"),
94
- isHydrated,
95
- };
96
- }, [lookup.state, isHydrated]);
97
- // ─── Auto-register MCP tools as frontend tools in modelContext ─────
98
- // Build the toolkit from connected servers; re-register when the visible
99
- // tool surface changes. Tool names are prefixed with the server id to
100
- // avoid collisions across connected servers — connector ids must not
101
- // contain `__` (enforced by `defineConnector`); `addCustomServer`
102
- // generates UUIDs that satisfy the constraint by construction.
103
- const toolkit = tapMemo(() => {
104
- const out = {};
105
- for (const server of state.servers) {
106
- if (server.connectionState !== "connected")
107
- continue;
108
- for (const tool of server.tools) {
109
- const fullName = `${server.id}__${tool.name}`;
110
- out[fullName] = {
111
- type: "frontend",
112
- ...(tool.description !== undefined
113
- ? { description: tool.description }
114
- : {}),
115
- parameters: tool.inputSchema,
116
- execute: (args) => lookup
117
- .get({ key: server.id })
118
- .callTool(tool.name, args),
119
- };
120
- }
121
- }
122
- return out;
123
- }, [state, lookup]);
124
- const clientRef = tapAssistantClientRef();
125
- tapEffect(() => {
126
- const client = clientRef.current;
127
- if (!client)
128
- return;
129
- return client.modelContext().register({
130
- getModelContext: () => ({ tools: toolkit }),
131
- });
132
- }, [toolkit, clientRef]);
133
- const serverByKind = (kind, index) => {
134
- const list = kind === "connector" ? state.connectors : state.customServers;
135
- const entry = list[index];
136
- if (!entry) {
137
- throw new Error(`McpManagerResource: no ${kind} at index ${index} (length ${list.length})`);
138
- }
139
- return lookup.get({ key: entry.id });
140
- };
141
- return {
142
- getState: () => state,
143
- server: (query) => {
144
- if ("id" in query)
145
- return lookup.get({ key: query.id });
146
- return serverByKind(query.kind, query.index);
147
- },
148
- connector: ({ index }) => serverByKind("connector", index),
149
- customServer: ({ index }) => serverByKind("custom", index),
150
- addCustomServer: async ({ name, url, auth }) => {
151
- const record = {
152
- id: typeof crypto !== "undefined" && "randomUUID" in crypto
153
- ? crypto.randomUUID()
154
- : `mcp-${Date.now()}-${Math.random().toString(36).slice(2)}`,
155
- name,
156
- url,
157
- auth: auth,
158
- createdAt: Date.now(),
159
- };
160
- setCustomServers((prev) => [...prev, record]);
161
- return record.id;
162
- },
163
- removeServer: async (id) => {
164
- // removeServer is custom-server only — connectors are app-defined
165
- // and not user-removable. Refuse rather than silently no-op.
166
- if (state.connectors.some((c) => c.id === id)) {
167
- throw new Error(`Cannot remove connector "${id}" — connectors are app-defined and not removable. Use a custom server id instead.`);
168
- }
169
- // Delegate to McpServerResource.remove() which disconnects,
170
- // clears auth state, and unregisters from customServers in one
171
- // place. Fallback to manual cleanup if the lookup is empty
172
- // (server already gone).
173
- try {
174
- await lookup.get({ key: id }).remove();
175
- }
176
- catch {
177
- await storage.clearAuthState(id);
178
- setCustomServers((prev) => prev.filter((s) => s.id !== id));
179
- }
180
- },
181
- };
11
+ const McpManagerResource = resource((props) => {
12
+ const connectors = props.connectors ?? [];
13
+ const autoConnect = props.autoConnect ?? true;
14
+ const redirectUri = props.oauthRedirectUri ?? defaultRedirectUri();
15
+ const storage = tapResource(props.storage ?? McpLocalStorage());
16
+ const [customServers, setCustomServers] = tapState([]);
17
+ const [isHydrated, setIsHydrated] = tapState(false);
18
+ const hydratedRef = tapRef(false);
19
+ const hydrate = tapEffectEvent(async (signal) => {
20
+ try {
21
+ const records = await storage.loadCustomServers();
22
+ if (signal.cancelled) return;
23
+ setCustomServers((prev) => {
24
+ if (prev.length === 0) return records;
25
+ const persistedIds = new Set(records.map((r) => r.id));
26
+ return [...records, ...prev.filter((r) => !persistedIds.has(r.id))];
27
+ });
28
+ } finally {
29
+ if (!signal.cancelled) {
30
+ hydratedRef.current = true;
31
+ setIsHydrated(true);
32
+ }
33
+ }
34
+ });
35
+ tapEffect(() => {
36
+ const signal = { cancelled: false };
37
+ hydrate(signal);
38
+ return () => {
39
+ signal.cancelled = true;
40
+ };
41
+ }, []);
42
+ const persistCustomServers = tapEffectEvent(async (records) => {
43
+ if (!hydratedRef.current) return;
44
+ await storage.saveCustomServers(records);
45
+ });
46
+ tapEffect(() => {
47
+ persistCustomServers(customServers);
48
+ }, [customServers]);
49
+ const serverElements = tapMemo(() => {
50
+ const connectorElements = connectors.map((c) => withKey(c.id, McpServerResource({
51
+ id: c.id,
52
+ kind: "connector",
53
+ name: c.name,
54
+ url: c.url,
55
+ icon: c.icon,
56
+ auth: c.auth,
57
+ storage,
58
+ redirectUri,
59
+ autoConnect,
60
+ onRemove: async () => {}
61
+ })));
62
+ const customElements = customServers.map((s) => withKey(s.id, McpServerResource({
63
+ id: s.id,
64
+ kind: "custom",
65
+ name: s.name,
66
+ url: s.url,
67
+ auth: s.auth,
68
+ storage,
69
+ redirectUri,
70
+ autoConnect,
71
+ onRemove: async () => {
72
+ setCustomServers((prev) => prev.filter((x) => x.id !== s.id));
73
+ }
74
+ })));
75
+ return [...connectorElements, ...customElements];
76
+ }, [
77
+ connectors,
78
+ customServers,
79
+ storage,
80
+ redirectUri,
81
+ autoConnect
82
+ ]);
83
+ const lookup = tapClientLookup(() => serverElements, [serverElements]);
84
+ const state = tapMemo(() => {
85
+ const all = lookup.state;
86
+ return {
87
+ servers: all,
88
+ connectors: all.filter((s) => s.kind === "connector"),
89
+ customServers: all.filter((s) => s.kind === "custom"),
90
+ isHydrated
91
+ };
92
+ }, [lookup.state, isHydrated]);
93
+ const toolkit = tapMemo(() => {
94
+ const out = {};
95
+ for (const server of state.servers) {
96
+ if (server.connectionState !== "connected") continue;
97
+ for (const tool of server.tools) {
98
+ const fullName = `${server.id}__${tool.name}`;
99
+ out[fullName] = {
100
+ type: "frontend",
101
+ ...tool.description !== void 0 ? { description: tool.description } : {},
102
+ parameters: tool.inputSchema,
103
+ execute: (args) => lookup.get({ key: server.id }).callTool(tool.name, args)
104
+ };
105
+ }
106
+ }
107
+ return out;
108
+ }, [state, lookup]);
109
+ const clientRef = tapAssistantClientRef();
110
+ tapEffect(() => {
111
+ const client = clientRef.current;
112
+ if (!client) return;
113
+ return client.modelContext().register({ getModelContext: () => ({ tools: toolkit }) });
114
+ }, [toolkit, clientRef]);
115
+ const serverByKind = (kind, index) => {
116
+ const list = kind === "connector" ? state.connectors : state.customServers;
117
+ const entry = list[index];
118
+ if (!entry) throw new Error(`McpManagerResource: no ${kind} at index ${index} (length ${list.length})`);
119
+ return lookup.get({ key: entry.id });
120
+ };
121
+ return {
122
+ getState: () => state,
123
+ server: (query) => {
124
+ if ("id" in query) return lookup.get({ key: query.id });
125
+ return serverByKind(query.kind, query.index);
126
+ },
127
+ connector: ({ index }) => serverByKind("connector", index),
128
+ customServer: ({ index }) => serverByKind("custom", index),
129
+ addCustomServer: async ({ name, url, auth }) => {
130
+ const record = {
131
+ id: typeof crypto !== "undefined" && "randomUUID" in crypto ? crypto.randomUUID() : `mcp-${Date.now()}-${Math.random().toString(36).slice(2)}`,
132
+ name,
133
+ url,
134
+ auth,
135
+ createdAt: Date.now()
136
+ };
137
+ setCustomServers((prev) => [...prev, record]);
138
+ return record.id;
139
+ },
140
+ removeServer: async (id) => {
141
+ if (state.connectors.some((c) => c.id === id)) throw new Error(`Cannot remove connector "${id}" — connectors are app-defined and not removable. Use a custom server id instead.`);
142
+ try {
143
+ await lookup.get({ key: id }).remove();
144
+ } catch {
145
+ await storage.clearAuthState(id);
146
+ setCustomServers((prev) => prev.filter((s) => s.id !== id));
147
+ }
148
+ }
149
+ };
182
150
  });
183
- // Ensure modelContext exists as a sibling when the manager mounts. If an
184
- // ancestor (e.g. a chat runtime) already provides modelContext, this is a
185
- // no-op; otherwise it's auto-mounted alongside `mcp`.
186
151
  attachTransformScopes(McpManagerResource, (scopes, parent) => {
187
- if (!scopes.modelContext && parent.modelContext.source === null) {
188
- scopes.modelContext = ModelContext();
189
- }
152
+ if (!scopes.modelContext && parent.modelContext.source === null) scopes.modelContext = ModelContext();
190
153
  });
154
+ //#endregion
155
+ export { McpManagerResource };
156
+
191
157
  //# sourceMappingURL=McpManagerResource.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"McpManagerResource.js","sourceRoot":"","sources":["../../src/resources/McpManagerResource.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"McpManagerResource.js","names":[],"sources":["../../src/resources/McpManagerResource.ts"],"sourcesContent":["import {\n resource,\n tapState,\n tapResource,\n tapEffect,\n tapMemo,\n tapEffectEvent,\n tapRef,\n withKey,\n} from \"@assistant-ui/tap\";\nimport {\n tapClientLookup,\n tapAssistantClientRef,\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 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};\n\nfunction defaultRedirectUri(): string {\n if (typeof window === \"undefined\") return \"\";\n return `${window.location.origin}/mcp/callback`;\n}\n\nexport const McpManagerResource = resource(\n (props: McpManagerResourceProps): ClientOutput<\"mcp\"> => {\n const connectors = props.connectors ?? [];\n const autoConnect = props.autoConnect ?? true;\n const redirectUri = props.oauthRedirectUri ?? defaultRedirectUri();\n\n const storageElement = props.storage ?? McpLocalStorage();\n const storage = tapResource(storageElement);\n\n const [customServers, setCustomServers] = tapState<MCPCustomServerRecord[]>(\n [],\n );\n const [isHydrated, setIsHydrated] = tapState(false);\n\n const hydratedRef = tapRef(false);\n\n const hydrate = tapEffectEvent(async (signal: { cancelled: boolean }) => {\n try {\n const records = await storage.loadCustomServers();\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 } finally {\n if (!signal.cancelled) {\n hydratedRef.current = true;\n setIsHydrated(true);\n }\n }\n });\n\n tapEffect(() => {\n const signal = { cancelled: false };\n void hydrate(signal);\n return () => {\n signal.cancelled = true;\n };\n }, []);\n\n const persistCustomServers = tapEffectEvent(\n async (records: MCPCustomServerRecord[]) => {\n if (!hydratedRef.current) return;\n await storage.saveCustomServers(records);\n },\n );\n\n tapEffect(() => {\n void persistCustomServers(customServers);\n }, [customServers]);\n\n const serverElements = tapMemo(() => {\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 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 onRemove: async () => {\n setCustomServers((prev) => prev.filter((x) => x.id !== s.id));\n },\n }),\n ),\n );\n return [...connectorElements, ...customElements];\n }, [connectors, customServers, storage, redirectUri, autoConnect]);\n\n const lookup = tapClientLookup(() => serverElements, [serverElements]);\n\n const state = tapMemo<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 = tapMemo<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\n .get({ key: server.id })\n .callTool(tool.name, args as unknown),\n };\n }\n }\n return out;\n }, [state, lookup]);\n\n const clientRef = tapAssistantClientRef();\n\n tapEffect(() => {\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 =\n 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 }) => {\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 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);\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(McpManagerResource, (scopes, parent) => {\n if (!scopes.modelContext && parent.modelContext.source === null) {\n scopes.modelContext = ModelContext();\n }\n});\n"],"mappings":"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"}
@@ -1,17 +1,21 @@
1
- import type { ClientOutput } from "@assistant-ui/store";
2
- import type { MCPStorage } from "./storage/types.js";
3
- import type { MCPAuthConfig, MCPServerKind } from "../mcp-scope.js";
4
- export type McpServerResourceProps = {
5
- id: string;
6
- kind: MCPServerKind;
7
- name: string;
8
- url: string;
9
- icon?: string | undefined;
10
- auth: MCPAuthConfig;
11
- storage: MCPStorage;
12
- redirectUri: string;
13
- autoConnect: boolean;
14
- onRemove: () => Promise<void>;
1
+ import { MCPAuthConfig, MCPServerKind } from "../mcp-scope.js";
2
+ import { MCPStorage } from "./storage/types.js";
3
+ import { ClientOutput } from "@assistant-ui/store";
4
+
5
+ //#region src/resources/McpServerResource.d.ts
6
+ type McpServerResourceProps = {
7
+ id: string;
8
+ kind: MCPServerKind;
9
+ name: string;
10
+ url: string;
11
+ icon?: string | undefined;
12
+ auth: MCPAuthConfig;
13
+ storage: MCPStorage;
14
+ redirectUri: string;
15
+ autoConnect: boolean;
16
+ onRemove: () => Promise<void>;
15
17
  };
16
- export declare const McpServerResource: (props: McpServerResourceProps) => import("@assistant-ui/tap").ResourceElement<ClientOutput<"mcpServer">, McpServerResourceProps>;
18
+ declare const McpServerResource: (props: McpServerResourceProps) => import("@assistant-ui/tap").ResourceElement<ClientOutput<"mcpServer">, McpServerResourceProps>;
19
+ //#endregion
20
+ export { McpServerResource, McpServerResourceProps };
17
21
  //# sourceMappingURL=McpServerResource.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"McpServerResource.d.ts","sourceRoot":"","sources":["../../src/resources/McpServerResource.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAWxD,OAAO,KAAK,EAAE,UAAU,EAAE,2BAAwB;AAClD,OAAO,KAAK,EACV,aAAa,EAEb,aAAa,EAGd,wBAAqB;AAEtB,MAAM,MAAM,sBAAsB,GAAG;IACnC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,aAAa,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,IAAI,EAAE,aAAa,CAAC;IACpB,OAAO,EAAE,UAAU,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,OAAO,CAAC;IACrB,QAAQ,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC/B,CAAC;AAEF,eAAO,MAAM,iBAAiB,mIA0P7B,CAAC"}
1
+ {"version":3,"file":"McpServerResource.d.ts","names":[],"sources":["../../src/resources/McpServerResource.ts"],"mappings":";;;;;KA4BY,sBAAA;EACV,EAAA;EACA,IAAA,EAAM,aAAA;EACN,IAAA;EACA,GAAA;EACA,IAAA;EACA,IAAA,EAAM,aAAA;EACN,OAAA,EAAS,UAAA;EACT,WAAA;EACA,WAAA;EACA,QAAA,QAAgB,OAAA;AAAA;AAAA,cAGL,iBAAA,GAAiB,KAAA,EAAA,sBAAA,iCAAA,eAAA,CAAA,YAAA,eAAA,sBAAA"}