@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,239 +1,190 @@
1
- import { resource, tapState, tapRef, tapEffect, tapMemo, tapEffectEvent, } from "@assistant-ui/tap";
2
- import { Client } from "@modelcontextprotocol/sdk/client/index.js";
3
- import { StreamableHTTPClientTransport, } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
4
- import { UnauthorizedError } from "@modelcontextprotocol/sdk/client/auth.js";
1
+ import { assertValidServerId } from "../utils/serverId.js";
5
2
  import { createOAuthProvider } from "../auth/createOAuthProvider.js";
6
3
  import { buildHeaders } from "../auth/buildHeaders.js";
7
- import { assertValidServerId } from "../utils/serverId.js";
8
- export const McpServerResource = resource((props) => {
9
- assertValidServerId(props.id);
10
- const [connectionState, setConnectionState] = tapState("disconnected");
11
- const [tools, setTools] = tapState([]);
12
- const [lastError, setLastError] = tapState(null);
13
- const [authorizationUrl, setAuthorizationUrl] = tapState(null);
14
- const clientRef = tapRef(null);
15
- const transportRef = tapRef(null);
16
- const buildTransport = tapEffectEvent(async () => {
17
- if (props.auth.type === "oauth") {
18
- const authProvider = createOAuthProvider({
19
- serverId: props.id,
20
- config: props.auth,
21
- storage: props.storage,
22
- redirectUri: props.redirectUri,
23
- onAuthorizationUrl: (url) => setAuthorizationUrl(url.toString()),
24
- });
25
- return new StreamableHTTPClientTransport(new URL(props.url), {
26
- authProvider,
27
- });
28
- }
29
- if (props.auth.type === "bearer") {
30
- const persisted = await props.storage.loadAuthState(props.id);
31
- const headers = buildHeaders(props.auth, persisted);
32
- const transportOpts = {};
33
- if (headers)
34
- transportOpts.requestInit = { headers };
35
- return new StreamableHTTPClientTransport(new URL(props.url), transportOpts);
36
- }
37
- return new StreamableHTTPClientTransport(new URL(props.url));
38
- });
39
- const finalizeConnect = tapEffectEvent(async (transport) => {
40
- const client = new Client({
41
- name: "assistant-ui-mcp",
42
- version: "0.0.0",
43
- });
44
- // SDK's StreamableHTTPClientTransport.sessionId is `string | undefined`
45
- // but Transport.sessionId is declared `string?` — under
46
- // exactOptionalPropertyTypes the SDK's own classes don't satisfy its
47
- // Transport interface. Cast to bridge the gap.
48
- await client.connect(transport);
49
- // Defer ref assignment until listTools() also succeeds — otherwise a
50
- // post-connect failure leaves stale refs that `callTool()` would
51
- // happily walk into, producing confusing SDK errors instead of
52
- // "not connected".
53
- const list = await client.listTools();
54
- clientRef.current = client;
55
- transportRef.current = transport;
56
- setTools(list.tools.map((t) => {
57
- const info = {
58
- name: t.name,
59
- inputSchema: t.inputSchema,
60
- };
61
- if (t.description !== undefined)
62
- info.description = t.description;
63
- return info;
64
- }));
65
- setConnectionState("connected");
66
- });
67
- const closeTransport = async () => {
68
- const t = transportRef.current;
69
- transportRef.current = null;
70
- clientRef.current = null;
71
- if (t) {
72
- try {
73
- await t.close();
74
- }
75
- catch {
76
- // ignore close errors
77
- }
78
- }
79
- };
80
- const doConnect = tapEffectEvent(async () => {
81
- // Close any prior transport/client so a re-connect doesn't leak.
82
- await closeTransport();
83
- setConnectionState("connecting");
84
- setLastError(null);
85
- setAuthorizationUrl(null);
86
- // Clear tools so a reconnect (error → connect, or authRequired
87
- // → connect) doesn't expose the previous attempt's tool list.
88
- setTools([]);
89
- let transport = null;
90
- try {
91
- transport = await buildTransport();
92
- // Don't assign to transportRef until connect succeeds — otherwise a
93
- // failed `listTools()` leaves an orphaned transport that future
94
- // doConnect / doDisconnect calls treat as live.
95
- await finalizeConnect(transport);
96
- }
97
- catch (err) {
98
- if (err instanceof UnauthorizedError) {
99
- // OAuth: keep the transport alive so completeAuth can call
100
- // finishAuth on it. Closing it before storing would leave a
101
- // closed transport on transportRef.
102
- transportRef.current = transport;
103
- setConnectionState("authRequired");
104
- }
105
- else {
106
- if (transport) {
107
- try {
108
- await transport.close();
109
- }
110
- catch {
111
- // ignore close errors
112
- }
113
- }
114
- setLastError({
115
- message: err instanceof Error ? err.message : String(err),
116
- });
117
- setConnectionState("error");
118
- }
119
- }
120
- });
121
- const doDisconnect = tapEffectEvent(async () => {
122
- setTools([]);
123
- setAuthorizationUrl(null);
124
- setConnectionState("disconnected");
125
- await closeTransport();
126
- });
127
- const doCompleteAuth = tapEffectEvent(async (callbackUrl) => {
128
- setConnectionState("authPending");
129
- setLastError(null);
130
- try {
131
- const url = new URL(callbackUrl);
132
- const code = url.searchParams.get("code");
133
- if (!code)
134
- throw new Error("missing authorization code in callback URL");
135
- let transport = transportRef.current;
136
- if (!transport) {
137
- transport = await buildTransport();
138
- transportRef.current = transport;
139
- }
140
- await transport.finishAuth(code);
141
- setAuthorizationUrl(null);
142
- await finalizeConnect(transport);
143
- }
144
- catch (err) {
145
- await closeTransport();
146
- setLastError({
147
- message: err instanceof Error ? err.message : String(err),
148
- });
149
- setConnectionState("error");
150
- }
151
- });
152
- const tryAutoConnect = tapEffectEvent(async (signal) => {
153
- if (!props.autoConnect)
154
- return;
155
- if (props.auth.type === "none") {
156
- void doConnect();
157
- return;
158
- }
159
- // Static connector token short-circuits the storage read.
160
- if (props.auth.type === "bearer" && props.auth.token) {
161
- void doConnect();
162
- return;
163
- }
164
- const persisted = await props.storage.loadAuthState(props.id);
165
- if (signal.cancelled)
166
- return;
167
- if (props.auth.type === "oauth") {
168
- if (!persisted?.tokens)
169
- return;
170
- }
171
- else if (!persisted?.token) {
172
- return;
173
- }
174
- void doConnect();
175
- });
176
- // Auto-connect on mount when usable auth exists.
177
- tapEffect(() => {
178
- const signal = { cancelled: false };
179
- void tryAutoConnect(signal);
180
- return () => {
181
- signal.cancelled = true;
182
- const t = transportRef.current;
183
- transportRef.current = null;
184
- clientRef.current = null;
185
- if (t)
186
- t.close().catch(() => { });
187
- };
188
- }, []);
189
- const state = tapMemo(() => ({
190
- id: props.id,
191
- kind: props.kind,
192
- name: props.name,
193
- url: props.url,
194
- icon: props.icon,
195
- connectionState,
196
- lastError,
197
- tools,
198
- authorizationUrl,
199
- }), [
200
- props.id,
201
- props.kind,
202
- props.name,
203
- props.url,
204
- props.icon,
205
- connectionState,
206
- lastError,
207
- tools,
208
- authorizationUrl,
209
- ]);
210
- return {
211
- getState: () => state,
212
- connect: doConnect,
213
- disconnect: doDisconnect,
214
- remove: async () => {
215
- await doDisconnect();
216
- await props.storage.clearAuthState(props.id);
217
- await props.onRemove();
218
- },
219
- callTool: async (name, args) => {
220
- const client = clientRef.current;
221
- if (!client) {
222
- throw new Error(`MCP server "${props.id}" is not connected`);
223
- }
224
- return await client.callTool({
225
- name,
226
- arguments: args,
227
- });
228
- },
229
- readResource: async (uri) => {
230
- const client = clientRef.current;
231
- if (!client) {
232
- throw new Error(`MCP server "${props.id}" is not connected`);
233
- }
234
- return await client.readResource({ uri });
235
- },
236
- completeAuth: doCompleteAuth,
237
- };
4
+ import { resource, tapEffect, tapEffectEvent, tapMemo, tapRef, tapState } from "@assistant-ui/tap";
5
+ import { Client } from "@modelcontextprotocol/sdk/client/index.js";
6
+ import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
7
+ import { UnauthorizedError } from "@modelcontextprotocol/sdk/client/auth.js";
8
+ //#region src/resources/McpServerResource.ts
9
+ const McpServerResource = resource((props) => {
10
+ assertValidServerId(props.id);
11
+ const [connectionState, setConnectionState] = tapState("disconnected");
12
+ const [tools, setTools] = tapState([]);
13
+ const [lastError, setLastError] = tapState(null);
14
+ const [authorizationUrl, setAuthorizationUrl] = tapState(null);
15
+ const clientRef = tapRef(null);
16
+ const transportRef = tapRef(null);
17
+ const buildTransport = tapEffectEvent(async () => {
18
+ if (props.auth.type === "oauth") {
19
+ const authProvider = createOAuthProvider({
20
+ serverId: props.id,
21
+ config: props.auth,
22
+ storage: props.storage,
23
+ redirectUri: props.redirectUri,
24
+ onAuthorizationUrl: (url) => setAuthorizationUrl(url.toString())
25
+ });
26
+ return new StreamableHTTPClientTransport(new URL(props.url), { authProvider });
27
+ }
28
+ if (props.auth.type === "bearer") {
29
+ const persisted = await props.storage.loadAuthState(props.id);
30
+ const headers = buildHeaders(props.auth, persisted);
31
+ const transportOpts = {};
32
+ if (headers) transportOpts.requestInit = { headers };
33
+ return new StreamableHTTPClientTransport(new URL(props.url), transportOpts);
34
+ }
35
+ return new StreamableHTTPClientTransport(new URL(props.url));
36
+ });
37
+ const finalizeConnect = tapEffectEvent(async (transport) => {
38
+ const client = new Client({
39
+ name: "assistant-ui-mcp",
40
+ version: "0.0.0"
41
+ });
42
+ await client.connect(transport);
43
+ const list = await client.listTools();
44
+ clientRef.current = client;
45
+ transportRef.current = transport;
46
+ setTools(list.tools.map((t) => {
47
+ const info = {
48
+ name: t.name,
49
+ inputSchema: t.inputSchema
50
+ };
51
+ if (t.description !== void 0) info.description = t.description;
52
+ return info;
53
+ }));
54
+ setConnectionState("connected");
55
+ });
56
+ const closeTransport = async () => {
57
+ const t = transportRef.current;
58
+ transportRef.current = null;
59
+ clientRef.current = null;
60
+ if (t) try {
61
+ await t.close();
62
+ } catch {}
63
+ };
64
+ const doConnect = tapEffectEvent(async () => {
65
+ await closeTransport();
66
+ setConnectionState("connecting");
67
+ setLastError(null);
68
+ setAuthorizationUrl(null);
69
+ setTools([]);
70
+ let transport = null;
71
+ try {
72
+ transport = await buildTransport();
73
+ await finalizeConnect(transport);
74
+ } catch (err) {
75
+ if (err instanceof UnauthorizedError) {
76
+ transportRef.current = transport;
77
+ setConnectionState("authRequired");
78
+ } else {
79
+ if (transport) try {
80
+ await transport.close();
81
+ } catch {}
82
+ setLastError({ message: err instanceof Error ? err.message : String(err) });
83
+ setConnectionState("error");
84
+ }
85
+ }
86
+ });
87
+ const doDisconnect = tapEffectEvent(async () => {
88
+ setTools([]);
89
+ setAuthorizationUrl(null);
90
+ setConnectionState("disconnected");
91
+ await closeTransport();
92
+ });
93
+ const doCompleteAuth = tapEffectEvent(async (callbackUrl) => {
94
+ setConnectionState("authPending");
95
+ setLastError(null);
96
+ try {
97
+ const code = new URL(callbackUrl).searchParams.get("code");
98
+ if (!code) throw new Error("missing authorization code in callback URL");
99
+ let transport = transportRef.current;
100
+ if (!transport) {
101
+ transport = await buildTransport();
102
+ transportRef.current = transport;
103
+ }
104
+ await transport.finishAuth(code);
105
+ setAuthorizationUrl(null);
106
+ await finalizeConnect(transport);
107
+ } catch (err) {
108
+ await closeTransport();
109
+ setLastError({ message: err instanceof Error ? err.message : String(err) });
110
+ setConnectionState("error");
111
+ }
112
+ });
113
+ const tryAutoConnect = tapEffectEvent(async (signal) => {
114
+ if (!props.autoConnect) return;
115
+ if (props.auth.type === "none") {
116
+ doConnect();
117
+ return;
118
+ }
119
+ if (props.auth.type === "bearer" && props.auth.token) {
120
+ doConnect();
121
+ return;
122
+ }
123
+ const persisted = await props.storage.loadAuthState(props.id);
124
+ if (signal.cancelled) return;
125
+ if (props.auth.type === "oauth") {
126
+ if (!persisted?.tokens) return;
127
+ } else if (!persisted?.token) return;
128
+ doConnect();
129
+ });
130
+ tapEffect(() => {
131
+ const signal = { cancelled: false };
132
+ tryAutoConnect(signal);
133
+ return () => {
134
+ signal.cancelled = true;
135
+ const t = transportRef.current;
136
+ transportRef.current = null;
137
+ clientRef.current = null;
138
+ if (t) t.close().catch(() => {});
139
+ };
140
+ }, []);
141
+ const state = tapMemo(() => ({
142
+ id: props.id,
143
+ kind: props.kind,
144
+ name: props.name,
145
+ url: props.url,
146
+ icon: props.icon,
147
+ connectionState,
148
+ lastError,
149
+ tools,
150
+ authorizationUrl
151
+ }), [
152
+ props.id,
153
+ props.kind,
154
+ props.name,
155
+ props.url,
156
+ props.icon,
157
+ connectionState,
158
+ lastError,
159
+ tools,
160
+ authorizationUrl
161
+ ]);
162
+ return {
163
+ getState: () => state,
164
+ connect: doConnect,
165
+ disconnect: doDisconnect,
166
+ remove: async () => {
167
+ await doDisconnect();
168
+ await props.storage.clearAuthState(props.id);
169
+ await props.onRemove();
170
+ },
171
+ callTool: async (name, args) => {
172
+ const client = clientRef.current;
173
+ if (!client) throw new Error(`MCP server "${props.id}" is not connected`);
174
+ return await client.callTool({
175
+ name,
176
+ arguments: args
177
+ });
178
+ },
179
+ readResource: async (uri) => {
180
+ const client = clientRef.current;
181
+ if (!client) throw new Error(`MCP server "${props.id}" is not connected`);
182
+ return await client.readResource({ uri });
183
+ },
184
+ completeAuth: doCompleteAuth
185
+ };
238
186
  });
187
+ //#endregion
188
+ export { McpServerResource };
189
+
239
190
  //# sourceMappingURL=McpServerResource.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"McpServerResource.js","sourceRoot":"","sources":["../../src/resources/McpServerResource.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"McpServerResource.js","names":[],"sources":["../../src/resources/McpServerResource.ts"],"sourcesContent":["import {\n resource,\n tapState,\n tapRef,\n tapEffect,\n tapMemo,\n tapEffectEvent,\n} 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 onRemove: () => Promise<void>;\n};\n\nexport const McpServerResource = resource(\n (props: McpServerResourceProps): ClientOutput<\"mcpServer\"> => {\n assertValidServerId(props.id);\n const [connectionState, setConnectionState] =\n tapState<MCPConnectionState>(\"disconnected\");\n const [tools, setTools] = tapState<MCPToolInfo[]>([]);\n const [lastError, setLastError] = tapState<{ message: string } | null>(\n null,\n );\n const [authorizationUrl, setAuthorizationUrl] = tapState<string | null>(\n null,\n );\n\n const clientRef = tapRef<Client | null>(null);\n const transportRef = tapRef<StreamableHTTPClientTransport | null>(null);\n\n const buildTransport = tapEffectEvent(\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 = tapEffectEvent(\n async (transport: StreamableHTTPClientTransport) => {\n const client = new Client({\n name: \"assistant-ui-mcp\",\n version: \"0.0.0\",\n });\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 client.connect(transport as unknown as Transport);\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 client.listTools();\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 },\n );\n\n const closeTransport = async () => {\n const t = transportRef.current;\n transportRef.current = null;\n clientRef.current = null;\n if (t) {\n try {\n await t.close();\n } catch {\n // ignore close errors\n }\n }\n };\n\n const doConnect = tapEffectEvent(async () => {\n // Close any prior transport/client so a re-connect doesn't leak.\n await closeTransport();\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 // 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);\n } catch (err) {\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 transportRef.current = transport;\n setConnectionState(\"authRequired\");\n } else {\n if (transport) {\n try {\n await transport.close();\n } catch {\n // ignore close errors\n }\n }\n setLastError({\n message: err instanceof Error ? err.message : String(err),\n });\n setConnectionState(\"error\");\n }\n }\n });\n\n const doDisconnect = tapEffectEvent(async () => {\n setTools([]);\n setAuthorizationUrl(null);\n setConnectionState(\"disconnected\");\n await closeTransport();\n });\n\n const doCompleteAuth = tapEffectEvent(async (callbackUrl: string) => {\n setConnectionState(\"authPending\");\n setLastError(null);\n try {\n const url = new URL(callbackUrl);\n const code = url.searchParams.get(\"code\");\n if (!code)\n throw new Error(\"missing authorization code in callback URL\");\n let transport = transportRef.current;\n if (!transport) {\n transport = await buildTransport();\n transportRef.current = transport;\n }\n await transport.finishAuth(code);\n setAuthorizationUrl(null);\n await finalizeConnect(transport);\n } catch (err) {\n await closeTransport();\n setLastError({\n message: err instanceof Error ? err.message : String(err),\n });\n setConnectionState(\"error\");\n }\n });\n\n const tryAutoConnect = tapEffectEvent(\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 tapEffect(() => {\n const signal = { cancelled: false };\n void tryAutoConnect(signal);\n return () => {\n signal.cancelled = true;\n const t = transportRef.current;\n transportRef.current = null;\n clientRef.current = null;\n if (t) t.close().catch(() => {});\n };\n }, []);\n\n const state = tapMemo<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 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);\n"],"mappings":"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"}
@@ -1,3 +1,7 @@
1
- import type { MCPStorage } from "./types.js";
2
- export declare const McpCustomStorage: (props: MCPStorage) => import("@assistant-ui/tap").ResourceElement<MCPStorage, MCPStorage>;
1
+ import { MCPStorage } from "./types.js";
2
+
3
+ //#region src/resources/storage/McpCustomStorage.d.ts
4
+ declare const McpCustomStorage: (props: MCPStorage) => import("@assistant-ui/tap").ResourceElement<MCPStorage, MCPStorage>;
5
+ //#endregion
6
+ export { McpCustomStorage };
3
7
  //# sourceMappingURL=McpCustomStorage.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"McpCustomStorage.d.ts","sourceRoot":"","sources":["../../../src/resources/storage/McpCustomStorage.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,mBAAgB;AAE1C,eAAO,MAAM,gBAAgB,4FAE5B,CAAC"}
1
+ {"version":3,"file":"McpCustomStorage.d.ts","names":[],"sources":["../../../src/resources/storage/McpCustomStorage.ts"],"mappings":";;;cAGa,gBAAA,GAAgB,KAAA,EAAA,UAAA,iCAAA,eAAA,CAAA,UAAA,EAAA,UAAA"}
@@ -1,3 +1,7 @@
1
1
  import { resource } from "@assistant-ui/tap";
2
- export const McpCustomStorage = resource((impl) => impl);
2
+ //#region src/resources/storage/McpCustomStorage.ts
3
+ const McpCustomStorage = resource((impl) => impl);
4
+ //#endregion
5
+ export { McpCustomStorage };
6
+
3
7
  //# sourceMappingURL=McpCustomStorage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"McpCustomStorage.js","sourceRoot":"","sources":["../../../src/resources/storage/McpCustomStorage.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAG7C,MAAM,CAAC,MAAM,gBAAgB,GAAG,QAAQ,CACtC,CAAC,IAAgB,EAAc,EAAE,CAAC,IAAI,CACvC,CAAC"}
1
+ {"version":3,"file":"McpCustomStorage.js","names":[],"sources":["../../../src/resources/storage/McpCustomStorage.ts"],"sourcesContent":["import { resource } from \"@assistant-ui/tap\";\nimport type { MCPStorage } from \"./types\";\n\nexport const McpCustomStorage = resource(\n (impl: MCPStorage): MCPStorage => impl,\n);\n"],"mappings":";;AAGA,MAAa,mBAAmB,UAC7B,SAAiC,IACpC"}
@@ -1,9 +1,11 @@
1
- import type { MCPStorage } from "./types.js";
2
- export type McpLocalStorageOptions = {
3
- /** Namespace prefix for keys. Default "aui-mcp". */
4
- keyPrefix?: string;
5
- /** Override the underlying Storage. Defaults to globalThis.localStorage. */
6
- storage?: Storage;
1
+ import { MCPStorage } from "./types.js";
2
+
3
+ //#region src/resources/storage/McpLocalStorage.d.ts
4
+ type McpLocalStorageOptions = {
5
+ /** Namespace prefix for keys. Default "aui-mcp". */keyPrefix?: string; /** Override the underlying Storage. Defaults to globalThis.localStorage. */
6
+ storage?: Storage;
7
7
  };
8
- export declare const McpLocalStorage: () => import("@assistant-ui/tap").ResourceElement<MCPStorage, undefined>;
8
+ declare const McpLocalStorage: () => import("@assistant-ui/tap").ResourceElement<MCPStorage, undefined>;
9
+ //#endregion
10
+ export { McpLocalStorage, McpLocalStorageOptions };
9
11
  //# sourceMappingURL=McpLocalStorage.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"McpLocalStorage.d.ts","sourceRoot":"","sources":["../../../src/resources/storage/McpLocalStorage.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,mBAAgB;AAE1C,MAAM,MAAM,sBAAsB,GAAG;IACnC,oDAAoD;IACpD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,4EAA4E;IAC5E,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,CAAC;AAcF,eAAO,MAAM,eAAe,0EAoD3B,CAAC"}
1
+ {"version":3,"file":"McpLocalStorage.d.ts","names":[],"sources":["../../../src/resources/storage/McpLocalStorage.ts"],"mappings":";;;KAKY,sBAAA;sDAEV,SAAA,WAFgC;EAIhC,OAAA,GAAU,OAAO;AAAA;AAAA,cAeN,eAAA,oCAAe,eAAA,CAAA,UAAA"}