mcp-use 0.1.20 → 0.3.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 (140) hide show
  1. package/dist/chunk-2HFIPY7C.js +429 -0
  2. package/dist/chunk-4DEFXVWT.js +680 -0
  3. package/dist/chunk-JXLQRAW2.js +532 -0
  4. package/dist/chunk-SHUYVCID.js +6 -0
  5. package/dist/chunk-YUSC6R6V.js +299 -0
  6. package/dist/index.cjs +5762 -0
  7. package/dist/index.d.ts +7 -0
  8. package/dist/index.d.ts.map +1 -1
  9. package/dist/index.js +3767 -22
  10. package/dist/langfuse-YA2S23SM.js +13 -0
  11. package/dist/src/agents/remote.d.ts.map +1 -1
  12. package/dist/src/agents/utils/ai_sdk.d.ts.map +1 -1
  13. package/dist/src/auth/browser-provider.d.ts +52 -0
  14. package/dist/src/auth/browser-provider.d.ts.map +1 -0
  15. package/dist/src/auth/callback.d.ts +6 -0
  16. package/dist/src/auth/callback.d.ts.map +1 -0
  17. package/dist/src/auth/index.d.ts +7 -0
  18. package/dist/src/auth/index.d.ts.map +1 -0
  19. package/dist/src/auth/types.d.ts +18 -0
  20. package/dist/src/auth/types.d.ts.map +1 -0
  21. package/dist/src/browser.cjs +323 -0
  22. package/dist/src/browser.d.ts +8 -0
  23. package/dist/src/browser.d.ts.map +1 -0
  24. package/dist/src/browser.js +9 -0
  25. package/dist/src/client/base.d.ts +32 -0
  26. package/dist/src/client/base.d.ts.map +1 -0
  27. package/dist/src/client.d.ts +19 -16
  28. package/dist/src/client.d.ts.map +1 -1
  29. package/dist/src/logging.d.ts +1 -1
  30. package/dist/src/logging.d.ts.map +1 -1
  31. package/dist/src/oauth-helper.d.ts +125 -0
  32. package/dist/src/oauth-helper.d.ts.map +1 -0
  33. package/dist/src/react/index.cjs +986 -0
  34. package/dist/src/react/index.d.ts +9 -0
  35. package/dist/src/react/index.d.ts.map +1 -0
  36. package/dist/src/react/index.js +11 -0
  37. package/dist/src/react/types.d.ts +139 -0
  38. package/dist/src/react/types.d.ts.map +1 -0
  39. package/dist/src/react/useMcp.d.ts +3 -0
  40. package/dist/src/react/useMcp.d.ts.map +1 -0
  41. package/dist/src/server/index.cjs +566 -0
  42. package/dist/src/server/index.d.ts +3 -0
  43. package/dist/src/server/index.d.ts.map +1 -0
  44. package/dist/src/server/index.js +9 -0
  45. package/dist/src/server/logging.d.ts +16 -0
  46. package/dist/src/server/logging.d.ts.map +1 -0
  47. package/dist/src/server/mcp-server.d.ts +282 -0
  48. package/dist/src/server/mcp-server.d.ts.map +1 -0
  49. package/dist/src/server/types.d.ts +47 -0
  50. package/dist/src/server/types.d.ts.map +1 -0
  51. package/dist/src/utils/assert.d.ts +8 -0
  52. package/dist/src/utils/assert.d.ts.map +1 -0
  53. package/dist/tsconfig.tsbuildinfo +1 -0
  54. package/package.json +72 -40
  55. package/dist/examples/add_server_tool.d.ts +0 -8
  56. package/dist/examples/add_server_tool.d.ts.map +0 -1
  57. package/dist/examples/add_server_tool.js +0 -79
  58. package/dist/examples/ai_sdk_example.d.ts +0 -23
  59. package/dist/examples/ai_sdk_example.d.ts.map +0 -1
  60. package/dist/examples/ai_sdk_example.js +0 -213
  61. package/dist/examples/airbnb_use.d.ts +0 -10
  62. package/dist/examples/airbnb_use.d.ts.map +0 -1
  63. package/dist/examples/airbnb_use.js +0 -43
  64. package/dist/examples/blender_use.d.ts +0 -15
  65. package/dist/examples/blender_use.d.ts.map +0 -1
  66. package/dist/examples/blender_use.js +0 -39
  67. package/dist/examples/browser_use.d.ts +0 -10
  68. package/dist/examples/browser_use.d.ts.map +0 -1
  69. package/dist/examples/browser_use.js +0 -46
  70. package/dist/examples/chat_example.d.ts +0 -10
  71. package/dist/examples/chat_example.d.ts.map +0 -1
  72. package/dist/examples/chat_example.js +0 -86
  73. package/dist/examples/filesystem_use.d.ts +0 -11
  74. package/dist/examples/filesystem_use.d.ts.map +0 -1
  75. package/dist/examples/filesystem_use.js +0 -43
  76. package/dist/examples/http_example.d.ts +0 -18
  77. package/dist/examples/http_example.d.ts.map +0 -1
  78. package/dist/examples/http_example.js +0 -37
  79. package/dist/examples/mcp_everything.d.ts +0 -6
  80. package/dist/examples/mcp_everything.d.ts.map +0 -1
  81. package/dist/examples/mcp_everything.js +0 -25
  82. package/dist/examples/multi_server_example.d.ts +0 -10
  83. package/dist/examples/multi_server_example.d.ts.map +0 -1
  84. package/dist/examples/multi_server_example.js +0 -51
  85. package/dist/examples/observability.d.ts +0 -6
  86. package/dist/examples/observability.d.ts.map +0 -1
  87. package/dist/examples/observability.js +0 -50
  88. package/dist/examples/stream_example.d.ts +0 -12
  89. package/dist/examples/stream_example.d.ts.map +0 -1
  90. package/dist/examples/stream_example.js +0 -198
  91. package/dist/examples/structured_output.d.ts +0 -9
  92. package/dist/examples/structured_output.d.ts.map +0 -1
  93. package/dist/examples/structured_output.js +0 -95
  94. package/dist/src/adapters/base.js +0 -124
  95. package/dist/src/adapters/index.js +0 -2
  96. package/dist/src/adapters/langchain_adapter.js +0 -49
  97. package/dist/src/agents/base.js +0 -9
  98. package/dist/src/agents/index.js +0 -3
  99. package/dist/src/agents/mcp_agent.js +0 -1002
  100. package/dist/src/agents/prompts/system_prompt_builder.js +0 -40
  101. package/dist/src/agents/prompts/templates.js +0 -39
  102. package/dist/src/agents/remote.js +0 -264
  103. package/dist/src/agents/utils/ai_sdk.js +0 -62
  104. package/dist/src/agents/utils/index.js +0 -1
  105. package/dist/src/client.js +0 -133
  106. package/dist/src/config.js +0 -34
  107. package/dist/src/connectors/base.js +0 -143
  108. package/dist/src/connectors/http.js +0 -150
  109. package/dist/src/connectors/index.js +0 -4
  110. package/dist/src/connectors/stdio.js +0 -68
  111. package/dist/src/connectors/websocket.js +0 -157
  112. package/dist/src/logging.js +0 -217
  113. package/dist/src/managers/index.js +0 -2
  114. package/dist/src/managers/server_manager.js +0 -106
  115. package/dist/src/managers/tools/acquire_active_mcp_server.js +0 -17
  116. package/dist/src/managers/tools/add_server_from_config.js +0 -40
  117. package/dist/src/managers/tools/base.js +0 -17
  118. package/dist/src/managers/tools/connect_mcp_server.js +0 -46
  119. package/dist/src/managers/tools/index.js +0 -5
  120. package/dist/src/managers/tools/list_mcp_servers.js +0 -33
  121. package/dist/src/managers/tools/release_mcp_server_connection.js +0 -19
  122. package/dist/src/observability/index.js +0 -12
  123. package/dist/src/observability/langfuse.js +0 -211
  124. package/dist/src/observability/manager.js +0 -199
  125. package/dist/src/observability/types.js +0 -4
  126. package/dist/src/session.js +0 -23
  127. package/dist/src/task_managers/base.js +0 -127
  128. package/dist/src/task_managers/index.js +0 -5
  129. package/dist/src/task_managers/sse.js +0 -43
  130. package/dist/src/task_managers/stdio.js +0 -51
  131. package/dist/src/task_managers/streamable_http.js +0 -50
  132. package/dist/src/task_managers/websocket.js +0 -67
  133. package/dist/src/telemetry/events.js +0 -44
  134. package/dist/src/telemetry/index.js +0 -8
  135. package/dist/src/telemetry/telemetry.js +0 -324
  136. package/dist/src/telemetry/utils.js +0 -39
  137. package/dist/tests/ai_sdk_compatibility.test.js +0 -214
  138. package/dist/tests/stream_events.test.js +0 -307
  139. package/dist/tests/stream_events_simple.test.js +0 -179
  140. package/dist/vitest.config.js +0 -21
@@ -0,0 +1,680 @@
1
+ import {
2
+ BrowserOAuthClientProvider
3
+ } from "./chunk-YUSC6R6V.js";
4
+ import {
5
+ __name
6
+ } from "./chunk-SHUYVCID.js";
7
+
8
+ // src/react/useMcp.ts
9
+ import {
10
+ CallToolResultSchema,
11
+ ListToolsResultSchema,
12
+ ListResourcesResultSchema,
13
+ ReadResourceResultSchema,
14
+ ListPromptsResultSchema,
15
+ GetPromptResultSchema
16
+ } from "@modelcontextprotocol/sdk/types.js";
17
+ import { useCallback, useEffect, useRef, useState } from "react";
18
+ import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
19
+ import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
20
+ import { Client } from "@modelcontextprotocol/sdk/client/index.js";
21
+ import { auth, UnauthorizedError } from "@modelcontextprotocol/sdk/client/auth.js";
22
+ import { sanitizeUrl } from "strict-url-sanitise";
23
+
24
+ // src/utils/assert.ts
25
+ function assert(condition, message) {
26
+ if (!condition) {
27
+ throw new Error(message);
28
+ }
29
+ }
30
+ __name(assert, "assert");
31
+
32
+ // src/react/useMcp.ts
33
+ var DEFAULT_RECONNECT_DELAY = 3e3;
34
+ var DEFAULT_RETRY_DELAY = 5e3;
35
+ var AUTH_TIMEOUT = 5 * 60 * 1e3;
36
+ function useMcp(options) {
37
+ const {
38
+ url,
39
+ enabled = true,
40
+ clientName,
41
+ clientUri,
42
+ callbackUrl = typeof window !== "undefined" ? sanitizeUrl(new URL("/oauth/callback", window.location.origin).toString()) : "/oauth/callback",
43
+ storageKeyPrefix = "mcp:auth",
44
+ clientConfig = {},
45
+ customHeaders = {},
46
+ debug: _debug = false,
47
+ autoRetry = false,
48
+ autoReconnect = DEFAULT_RECONNECT_DELAY,
49
+ transportType = "auto",
50
+ preventAutoAuth = false,
51
+ onPopupWindow
52
+ } = options;
53
+ const [state, setState] = useState("discovering");
54
+ const [tools, setTools] = useState([]);
55
+ const [resources, setResources] = useState([]);
56
+ const [resourceTemplates, setResourceTemplates] = useState([]);
57
+ const [prompts, setPrompts] = useState([]);
58
+ const [error, setError] = useState(void 0);
59
+ const [log, setLog] = useState([]);
60
+ const [authUrl, setAuthUrl] = useState(void 0);
61
+ const clientRef = useRef(null);
62
+ const transportRef = useRef(null);
63
+ const authProviderRef = useRef(null);
64
+ const connectingRef = useRef(false);
65
+ const isMountedRef = useRef(true);
66
+ const connectAttemptRef = useRef(0);
67
+ const authTimeoutRef = useRef(null);
68
+ const stateRef = useRef(state);
69
+ const autoReconnectRef = useRef(autoReconnect);
70
+ const successfulTransportRef = useRef(null);
71
+ useEffect(() => {
72
+ stateRef.current = state;
73
+ autoReconnectRef.current = autoReconnect;
74
+ }, [state, autoReconnect]);
75
+ const addLog = useCallback(
76
+ (level, message, ...args) => {
77
+ const fullMessage = args.length > 0 ? `${message} ${args.map((arg) => JSON.stringify(arg)).join(" ")}` : message;
78
+ console[level](`[useMcp] ${fullMessage}`);
79
+ if (isMountedRef.current) {
80
+ setLog((prevLog) => [...prevLog.slice(-100), { level, message: fullMessage, timestamp: Date.now() }]);
81
+ }
82
+ },
83
+ []
84
+ );
85
+ const disconnect = useCallback(
86
+ async (quiet = false) => {
87
+ if (!quiet) addLog("info", "Disconnecting...");
88
+ connectingRef.current = false;
89
+ if (authTimeoutRef.current) clearTimeout(authTimeoutRef.current);
90
+ authTimeoutRef.current = null;
91
+ const transport = transportRef.current;
92
+ clientRef.current = null;
93
+ transportRef.current = null;
94
+ if (isMountedRef.current && !quiet) {
95
+ setState("discovering");
96
+ setTools([]);
97
+ setResources([]);
98
+ setResourceTemplates([]);
99
+ setPrompts([]);
100
+ setError(void 0);
101
+ setAuthUrl(void 0);
102
+ }
103
+ if (transport) {
104
+ try {
105
+ await transport.close();
106
+ if (!quiet) addLog("debug", "Transport closed");
107
+ } catch (err) {
108
+ if (!quiet) addLog("warn", "Error closing transport:", err);
109
+ }
110
+ }
111
+ },
112
+ [addLog]
113
+ );
114
+ const failConnection = useCallback(
115
+ (errorMessage, connectionError) => {
116
+ addLog("error", errorMessage, connectionError ?? "");
117
+ if (isMountedRef.current) {
118
+ setState("failed");
119
+ setError(errorMessage);
120
+ const manualUrl = authProviderRef.current?.getLastAttemptedAuthUrl();
121
+ if (manualUrl) {
122
+ setAuthUrl(manualUrl);
123
+ addLog("info", "Manual authentication URL may be available.", manualUrl);
124
+ }
125
+ }
126
+ connectingRef.current = false;
127
+ },
128
+ [addLog]
129
+ );
130
+ const connect = useCallback(async () => {
131
+ if (!enabled || !url) {
132
+ addLog("debug", enabled ? "No server URL provided, skipping connection." : "Connection disabled via enabled flag.");
133
+ return;
134
+ }
135
+ if (connectingRef.current) {
136
+ addLog("debug", "Connection attempt already in progress.");
137
+ return;
138
+ }
139
+ if (!isMountedRef.current) {
140
+ addLog("debug", "Connect called after unmount, aborting.");
141
+ return;
142
+ }
143
+ connectingRef.current = true;
144
+ connectAttemptRef.current += 1;
145
+ setError(void 0);
146
+ setAuthUrl(void 0);
147
+ successfulTransportRef.current = null;
148
+ setState("discovering");
149
+ addLog("info", `Connecting attempt #${connectAttemptRef.current} to ${url}...`);
150
+ if (!authProviderRef.current) {
151
+ authProviderRef.current = new BrowserOAuthClientProvider(url, {
152
+ storageKeyPrefix,
153
+ clientName,
154
+ clientUri,
155
+ callbackUrl,
156
+ preventAutoAuth,
157
+ onPopupWindow
158
+ });
159
+ addLog("debug", "BrowserOAuthClientProvider initialized in connect.");
160
+ }
161
+ if (!clientRef.current) {
162
+ clientRef.current = new Client(
163
+ { name: clientConfig.name || "use-mcp-react-client", version: clientConfig.version || "0.1.0" },
164
+ { capabilities: {} }
165
+ );
166
+ addLog("debug", "MCP Client initialized in connect.");
167
+ }
168
+ const tryConnectWithTransport = /* @__PURE__ */ __name(async (transportTypeParam, isAuthRetry = false) => {
169
+ addLog("info", `Attempting connection with ${transportTypeParam.toUpperCase()} transport${isAuthRetry ? " (after auth)" : ""}...`);
170
+ if (stateRef.current !== "authenticating") {
171
+ setState("connecting");
172
+ }
173
+ let transportInstance;
174
+ try {
175
+ assert(authProviderRef.current, "Auth Provider must be initialized");
176
+ assert(clientRef.current, "Client must be initialized");
177
+ if (transportRef.current) {
178
+ await transportRef.current.close().catch((e) => addLog("warn", `Error closing previous transport: ${e.message}`));
179
+ transportRef.current = null;
180
+ }
181
+ const commonOptions = {
182
+ authProvider: authProviderRef.current,
183
+ requestInit: {
184
+ headers: {
185
+ Accept: "application/json, text/event-stream",
186
+ ...customHeaders
187
+ }
188
+ }
189
+ };
190
+ const sanitizedUrl = sanitizeUrl(url);
191
+ const targetUrl = new URL(sanitizedUrl);
192
+ addLog("debug", `Creating ${transportTypeParam.toUpperCase()} transport for URL: ${targetUrl.toString()}`);
193
+ if (transportTypeParam === "http") {
194
+ addLog("debug", "Creating StreamableHTTPClientTransport...");
195
+ transportInstance = new StreamableHTTPClientTransport(targetUrl, commonOptions);
196
+ addLog("debug", "StreamableHTTPClientTransport created successfully");
197
+ } else {
198
+ addLog("debug", "Creating SSEClientTransport...");
199
+ transportInstance = new SSEClientTransport(targetUrl, commonOptions);
200
+ addLog("debug", "SSEClientTransport created successfully");
201
+ }
202
+ transportRef.current = transportInstance;
203
+ addLog("debug", `${transportTypeParam.toUpperCase()} transport created and assigned to ref.`);
204
+ } catch (err) {
205
+ failConnection(
206
+ `Failed to create ${transportTypeParam.toUpperCase()} transport: ${err instanceof Error ? err.message : String(err)}`,
207
+ err instanceof Error ? err : void 0
208
+ );
209
+ return "failed";
210
+ }
211
+ transportInstance.onmessage = (message) => {
212
+ addLog("debug", `[Transport] Received: ${JSON.stringify(message)}`);
213
+ clientRef.current?.handleMessage?.(message);
214
+ };
215
+ transportInstance.onerror = (err) => {
216
+ addLog("warn", `Transport error event (${transportTypeParam.toUpperCase()}):`, err);
217
+ failConnection(`Transport error (${transportTypeParam.toUpperCase()}): ${err.message}`, err);
218
+ };
219
+ transportInstance.onclose = () => {
220
+ if (!isMountedRef.current || connectingRef.current) return;
221
+ addLog("info", `Transport connection closed (${successfulTransportRef.current || "unknown"} type).`);
222
+ const currentState = stateRef.current;
223
+ const currentAutoReconnect = autoReconnectRef.current;
224
+ if (currentState === "ready" && currentAutoReconnect) {
225
+ const delay = typeof currentAutoReconnect === "number" ? currentAutoReconnect : DEFAULT_RECONNECT_DELAY;
226
+ addLog("info", `Attempting to reconnect in ${delay}ms...`);
227
+ setState("connecting");
228
+ setTimeout(() => {
229
+ if (isMountedRef.current) {
230
+ connect();
231
+ }
232
+ }, delay);
233
+ } else if (currentState !== "failed" && currentState !== "authenticating") {
234
+ failConnection("Connection closed unexpectedly.");
235
+ }
236
+ };
237
+ try {
238
+ addLog("info", `Connecting client via ${transportTypeParam.toUpperCase()}...`);
239
+ await clientRef.current.connect(transportInstance);
240
+ addLog("info", `Client connected via ${transportTypeParam.toUpperCase()}. Loading tools, resources, and prompts...`);
241
+ successfulTransportRef.current = transportTypeParam;
242
+ setState("loading");
243
+ const toolsResponse = await clientRef.current.request({ method: "tools/list" }, ListToolsResultSchema);
244
+ let resourcesResponse = { resources: [], resourceTemplates: [] };
245
+ try {
246
+ resourcesResponse = await clientRef.current.request({ method: "resources/list" }, ListResourcesResultSchema);
247
+ } catch (err) {
248
+ addLog("debug", "Server does not support resources/list method", err);
249
+ }
250
+ let promptsResponse = { prompts: [] };
251
+ try {
252
+ promptsResponse = await clientRef.current.request({ method: "prompts/list" }, ListPromptsResultSchema);
253
+ } catch (err) {
254
+ addLog("debug", "Server does not support prompts/list method", err);
255
+ }
256
+ if (isMountedRef.current) {
257
+ setTools(toolsResponse.tools);
258
+ setResources(resourcesResponse.resources);
259
+ setResourceTemplates(Array.isArray(resourcesResponse.resourceTemplates) ? resourcesResponse.resourceTemplates : []);
260
+ setPrompts(promptsResponse.prompts);
261
+ const summary = [`Loaded ${toolsResponse.tools.length} tools`];
262
+ if (resourcesResponse.resources.length > 0 || resourcesResponse.resourceTemplates && resourcesResponse.resourceTemplates.length > 0) {
263
+ summary.push(`${resourcesResponse.resources.length} resources`);
264
+ if (Array.isArray(resourcesResponse.resourceTemplates) && resourcesResponse.resourceTemplates.length > 0) {
265
+ summary.push(`${resourcesResponse.resourceTemplates.length} resource templates`);
266
+ }
267
+ }
268
+ if (promptsResponse.prompts.length > 0) {
269
+ summary.push(`${promptsResponse.prompts.length} prompts`);
270
+ }
271
+ addLog("info", summary.join(", ") + ".");
272
+ setState("ready");
273
+ connectAttemptRef.current = 0;
274
+ return "success";
275
+ } else {
276
+ return "failed";
277
+ }
278
+ } catch (connectErr) {
279
+ addLog("debug", `Client connect error via ${transportTypeParam.toUpperCase()}:`, connectErr);
280
+ const errorInstance = connectErr instanceof Error ? connectErr : new Error(String(connectErr));
281
+ const errorMessage = errorInstance.message;
282
+ const is404 = errorMessage.includes("404") || errorMessage.includes("Not Found");
283
+ const is405 = errorMessage.includes("405") || errorMessage.includes("Method Not Allowed");
284
+ const isLikelyCors = errorMessage === "Failed to fetch" || errorMessage === "NetworkError when attempting to fetch resource." || errorMessage === "Load failed";
285
+ if (transportTypeParam === "http" && (is404 || is405 || isLikelyCors)) {
286
+ addLog("warn", `HTTP transport failed (${isLikelyCors ? "CORS" : is404 ? "404" : "405"}), will try fallback.`);
287
+ return "fallback";
288
+ }
289
+ if (errorInstance instanceof UnauthorizedError || errorMessage.includes("Unauthorized") || errorMessage.includes("401")) {
290
+ if (isAuthRetry) {
291
+ addLog("error", "Authentication failed even after successful token refresh. This may indicate a server issue.");
292
+ failConnection("Authentication loop detected - auth succeeded but connection still unauthorized.");
293
+ return "failed";
294
+ }
295
+ addLog("info", "Authentication required.");
296
+ assert(authProviderRef.current, "Auth Provider not available for auth flow");
297
+ const existingTokens = await authProviderRef.current.tokens();
298
+ if (preventAutoAuth && !existingTokens) {
299
+ addLog("info", "Authentication required but auto-auth prevented. User action needed.");
300
+ setState("pending_auth");
301
+ return "auth_redirect";
302
+ }
303
+ if (stateRef.current !== "authenticating" && stateRef.current !== "pending_auth") {
304
+ setState("authenticating");
305
+ if (authTimeoutRef.current) clearTimeout(authTimeoutRef.current);
306
+ authTimeoutRef.current = setTimeout(() => {
307
+ if (isMountedRef.current) {
308
+ const currentState = stateRef.current;
309
+ if (currentState === "authenticating") {
310
+ failConnection("Authentication timed out. Please try again.");
311
+ }
312
+ }
313
+ }, AUTH_TIMEOUT);
314
+ }
315
+ try {
316
+ assert(url, "Server URL is required for authentication");
317
+ const authResult = await auth(authProviderRef.current, { serverUrl: url });
318
+ if (!isMountedRef.current) return "failed";
319
+ if (authResult === "AUTHORIZED") {
320
+ addLog("info", "Authentication successful via existing token or refresh. Retrying transport connection...");
321
+ if (authTimeoutRef.current) clearTimeout(authTimeoutRef.current);
322
+ authTimeoutRef.current = null;
323
+ return await tryConnectWithTransport(transportTypeParam, true);
324
+ } else if (authResult === "REDIRECT") {
325
+ addLog("info", "Redirecting for authentication. Waiting for callback...");
326
+ return "auth_redirect";
327
+ }
328
+ } catch (sdkAuthError) {
329
+ if (!isMountedRef.current) return "failed";
330
+ if (authTimeoutRef.current) clearTimeout(authTimeoutRef.current);
331
+ failConnection(
332
+ `Failed to initiate authentication: ${sdkAuthError instanceof Error ? sdkAuthError.message : String(sdkAuthError)}`,
333
+ sdkAuthError instanceof Error ? sdkAuthError : void 0
334
+ );
335
+ return "failed";
336
+ }
337
+ }
338
+ failConnection(`Failed to connect via ${transportTypeParam.toUpperCase()}: ${errorMessage}`, errorInstance);
339
+ return "failed";
340
+ }
341
+ }, "tryConnectWithTransport");
342
+ let finalStatus = "failed";
343
+ if (transportType === "sse") {
344
+ addLog("debug", "Using SSE-only transport mode");
345
+ finalStatus = await tryConnectWithTransport("sse");
346
+ } else if (transportType === "http") {
347
+ addLog("debug", "Using HTTP-only transport mode");
348
+ finalStatus = await tryConnectWithTransport("http");
349
+ } else {
350
+ addLog("debug", "Using auto transport mode (HTTP with SSE fallback)");
351
+ const httpResult = await tryConnectWithTransport("http");
352
+ if (httpResult === "fallback" && isMountedRef.current && stateRef.current !== "authenticating") {
353
+ addLog("info", "HTTP failed, attempting SSE fallback...");
354
+ const sseResult = await tryConnectWithTransport("sse");
355
+ finalStatus = sseResult;
356
+ } else {
357
+ finalStatus = httpResult;
358
+ }
359
+ }
360
+ if (finalStatus === "success" || finalStatus === "failed") {
361
+ connectingRef.current = false;
362
+ }
363
+ addLog("debug", `Connection sequence finished with status: ${finalStatus}`);
364
+ }, [
365
+ addLog,
366
+ failConnection,
367
+ disconnect,
368
+ url,
369
+ storageKeyPrefix,
370
+ clientName,
371
+ clientUri,
372
+ callbackUrl,
373
+ clientConfig.name,
374
+ clientConfig.version,
375
+ customHeaders,
376
+ transportType,
377
+ preventAutoAuth,
378
+ onPopupWindow,
379
+ enabled
380
+ ]);
381
+ const callTool = useCallback(
382
+ async (name, args) => {
383
+ if (stateRef.current !== "ready" || !clientRef.current) {
384
+ throw new Error(`MCP client is not ready (current state: ${state}). Cannot call tool "${name}".`);
385
+ }
386
+ addLog("info", `Calling tool: ${name}`, args);
387
+ try {
388
+ const result = await clientRef.current.request({ method: "tools/call", params: { name, arguments: args } }, CallToolResultSchema);
389
+ addLog("info", `Tool "${name}" call successful:`, result);
390
+ return result;
391
+ } catch (err) {
392
+ addLog("error", `Error calling tool "${name}": ${err instanceof Error ? err.message : String(err)}`, err);
393
+ const errorInstance = err instanceof Error ? err : new Error(String(err));
394
+ if (errorInstance instanceof UnauthorizedError || errorInstance.message.includes("Unauthorized") || errorInstance.message.includes("401")) {
395
+ addLog("warn", "Tool call unauthorized, attempting re-authentication...");
396
+ setState("authenticating");
397
+ if (authTimeoutRef.current) clearTimeout(authTimeoutRef.current);
398
+ authTimeoutRef.current = setTimeout(() => {
399
+ if (isMountedRef.current) {
400
+ const currentState2 = stateRef.current;
401
+ if (currentState2 === "authenticating") {
402
+ failConnection("Authentication timed out. Please try again.");
403
+ }
404
+ }
405
+ }, AUTH_TIMEOUT);
406
+ try {
407
+ assert(authProviderRef.current, "Auth Provider not available for tool re-auth");
408
+ assert(url, "Server URL is required for authentication");
409
+ const authResult = await auth(authProviderRef.current, { serverUrl: url });
410
+ if (!isMountedRef.current) return;
411
+ if (authResult === "AUTHORIZED") {
412
+ addLog("info", "Re-authentication successful. Retrying tool call is recommended, or reconnecting.");
413
+ if (authTimeoutRef.current) clearTimeout(authTimeoutRef.current);
414
+ connectingRef.current = false;
415
+ connect();
416
+ } else if (authResult === "REDIRECT") {
417
+ addLog("info", "Redirecting for re-authentication for tool call.");
418
+ }
419
+ } catch (sdkAuthError) {
420
+ if (!isMountedRef.current) return;
421
+ if (authTimeoutRef.current) clearTimeout(authTimeoutRef.current);
422
+ failConnection(
423
+ `Re-authentication failed: ${sdkAuthError instanceof Error ? sdkAuthError.message : String(sdkAuthError)}`,
424
+ sdkAuthError instanceof Error ? sdkAuthError : void 0
425
+ );
426
+ }
427
+ }
428
+ const currentState = stateRef.current;
429
+ if (currentState !== "authenticating") {
430
+ throw err;
431
+ }
432
+ return void 0;
433
+ }
434
+ },
435
+ [state, url, addLog, failConnection, connect]
436
+ );
437
+ const retry = useCallback(() => {
438
+ if (stateRef.current === "failed") {
439
+ addLog("info", "Retry requested...");
440
+ connect();
441
+ } else {
442
+ addLog("warn", `Retry called but state is not 'failed' (state: ${stateRef.current}). Ignoring.`);
443
+ }
444
+ }, [addLog, connect]);
445
+ const authenticate = useCallback(async () => {
446
+ addLog("info", "Manual authentication requested...");
447
+ const currentState = stateRef.current;
448
+ if (currentState === "failed") {
449
+ addLog("info", "Attempting to reconnect and authenticate via retry...");
450
+ retry();
451
+ } else if (currentState === "pending_auth") {
452
+ addLog("info", "Proceeding with authentication from pending state...");
453
+ setState("authenticating");
454
+ if (authTimeoutRef.current) clearTimeout(authTimeoutRef.current);
455
+ authTimeoutRef.current = setTimeout(() => {
456
+ if (isMountedRef.current) {
457
+ const currentStateValue = stateRef.current;
458
+ if (currentStateValue === "authenticating") {
459
+ failConnection("Authentication timed out. Please try again.");
460
+ }
461
+ }
462
+ }, AUTH_TIMEOUT);
463
+ try {
464
+ assert(authProviderRef.current, "Auth Provider not available for manual auth");
465
+ assert(url, "Server URL is required for authentication");
466
+ const authResult = await auth(authProviderRef.current, { serverUrl: url });
467
+ if (!isMountedRef.current) return;
468
+ if (authResult === "AUTHORIZED") {
469
+ addLog("info", "Manual authentication successful. Re-attempting connection...");
470
+ if (authTimeoutRef.current) clearTimeout(authTimeoutRef.current);
471
+ connectingRef.current = false;
472
+ connect();
473
+ } else if (authResult === "REDIRECT") {
474
+ addLog("info", "Redirecting for manual authentication. Waiting for callback...");
475
+ }
476
+ } catch (authError) {
477
+ if (!isMountedRef.current) return;
478
+ if (authTimeoutRef.current) clearTimeout(authTimeoutRef.current);
479
+ failConnection(
480
+ `Manual authentication failed: ${authError instanceof Error ? authError.message : String(authError)}`,
481
+ authError instanceof Error ? authError : void 0
482
+ );
483
+ }
484
+ } else if (currentState === "authenticating") {
485
+ addLog("warn", "Already attempting authentication. Check for blocked popups or wait for timeout.");
486
+ const manualUrl = authProviderRef.current?.getLastAttemptedAuthUrl();
487
+ if (manualUrl && !authUrl) {
488
+ setAuthUrl(manualUrl);
489
+ addLog("info", "Manual authentication URL retrieved:", manualUrl);
490
+ }
491
+ } else {
492
+ addLog(
493
+ "info",
494
+ `Client not in a state requiring manual authentication trigger (state: ${currentState}). If needed, try disconnecting and reconnecting.`
495
+ );
496
+ }
497
+ }, [addLog, retry, authUrl, url, failConnection, connect]);
498
+ const clearStorage = useCallback(() => {
499
+ if (authProviderRef.current) {
500
+ const count = authProviderRef.current.clearStorage();
501
+ addLog("info", `Cleared ${count} item(s) from localStorage for ${url}.`);
502
+ setAuthUrl(void 0);
503
+ disconnect();
504
+ } else {
505
+ addLog("warn", "Auth provider not initialized, cannot clear storage.");
506
+ }
507
+ }, [url, addLog, disconnect]);
508
+ const listResources = useCallback(async () => {
509
+ if (stateRef.current !== "ready" || !clientRef.current) {
510
+ throw new Error(`MCP client is not ready (current state: ${state}). Cannot list resources.`);
511
+ }
512
+ addLog("info", "Listing resources...");
513
+ try {
514
+ const resourcesResponse = await clientRef.current.request({ method: "resources/list" }, ListResourcesResultSchema);
515
+ if (isMountedRef.current) {
516
+ setResources(resourcesResponse.resources);
517
+ setResourceTemplates(Array.isArray(resourcesResponse.resourceTemplates) ? resourcesResponse.resourceTemplates : []);
518
+ addLog(
519
+ "info",
520
+ `Listed ${resourcesResponse.resources.length} resources, ${Array.isArray(resourcesResponse.resourceTemplates) ? resourcesResponse.resourceTemplates.length : 0} resource templates.`
521
+ );
522
+ }
523
+ } catch (err) {
524
+ addLog("error", `Error listing resources: ${err instanceof Error ? err.message : String(err)}`, err);
525
+ throw err;
526
+ }
527
+ }, [state, addLog]);
528
+ const readResource = useCallback(
529
+ async (uri) => {
530
+ if (stateRef.current !== "ready" || !clientRef.current) {
531
+ throw new Error(`MCP client is not ready (current state: ${state}). Cannot read resource "${uri}".`);
532
+ }
533
+ addLog("info", `Reading resource: ${uri}`);
534
+ try {
535
+ const result = await clientRef.current.request({ method: "resources/read", params: { uri } }, ReadResourceResultSchema);
536
+ addLog("info", `Resource "${uri}" read successfully`);
537
+ return result;
538
+ } catch (err) {
539
+ addLog("error", `Error reading resource "${uri}": ${err instanceof Error ? err.message : String(err)}`, err);
540
+ throw err;
541
+ }
542
+ },
543
+ [state, addLog]
544
+ );
545
+ const listPrompts = useCallback(async () => {
546
+ if (stateRef.current !== "ready" || !clientRef.current) {
547
+ throw new Error(`MCP client is not ready (current state: ${state}). Cannot list prompts.`);
548
+ }
549
+ addLog("info", "Listing prompts...");
550
+ try {
551
+ const promptsResponse = await clientRef.current.request({ method: "prompts/list" }, ListPromptsResultSchema);
552
+ if (isMountedRef.current) {
553
+ setPrompts(promptsResponse.prompts);
554
+ addLog("info", `Listed ${promptsResponse.prompts.length} prompts.`);
555
+ }
556
+ } catch (err) {
557
+ addLog("error", `Error listing prompts: ${err instanceof Error ? err.message : String(err)}`, err);
558
+ throw err;
559
+ }
560
+ }, [state, addLog]);
561
+ const getPrompt = useCallback(
562
+ async (name, args) => {
563
+ if (stateRef.current !== "ready" || !clientRef.current) {
564
+ throw new Error(`MCP client is not ready (current state: ${state}). Cannot get prompt "${name}".`);
565
+ }
566
+ addLog("info", `Getting prompt: ${name}`, args);
567
+ try {
568
+ const result = await clientRef.current.request({ method: "prompts/get", params: { name, arguments: args } }, GetPromptResultSchema);
569
+ addLog("info", `Prompt "${name}" retrieved successfully`);
570
+ return result;
571
+ } catch (err) {
572
+ addLog("error", `Error getting prompt "${name}": ${err instanceof Error ? err.message : String(err)}`, err);
573
+ throw err;
574
+ }
575
+ },
576
+ [state, addLog]
577
+ );
578
+ const connectRef = useRef(connect);
579
+ const failConnectionRef = useRef(failConnection);
580
+ useEffect(() => {
581
+ connectRef.current = connect;
582
+ failConnectionRef.current = failConnection;
583
+ });
584
+ useEffect(() => {
585
+ const messageHandler = /* @__PURE__ */ __name((event) => {
586
+ if (event.origin !== window.location.origin) return;
587
+ if (event.data?.type === "mcp_auth_callback") {
588
+ addLog("info", "Received auth callback message.", event.data);
589
+ if (authTimeoutRef.current) clearTimeout(authTimeoutRef.current);
590
+ authTimeoutRef.current = null;
591
+ if (event.data.success) {
592
+ addLog("info", "Authentication successful via popup. Reconnecting client...");
593
+ if (!connectingRef.current) {
594
+ connectingRef.current = false;
595
+ connectRef.current();
596
+ } else {
597
+ addLog("warn", "Connection already in progress, skipping reconnection from auth callback");
598
+ }
599
+ } else {
600
+ failConnectionRef.current(`Authentication failed in callback: ${event.data.error || "Unknown reason."}`);
601
+ }
602
+ }
603
+ }, "messageHandler");
604
+ window.addEventListener("message", messageHandler);
605
+ addLog("debug", "Auth callback message listener added.");
606
+ return () => {
607
+ window.removeEventListener("message", messageHandler);
608
+ addLog("debug", "Auth callback message listener removed.");
609
+ if (authTimeoutRef.current) clearTimeout(authTimeoutRef.current);
610
+ };
611
+ }, [addLog]);
612
+ useEffect(() => {
613
+ isMountedRef.current = true;
614
+ if (!enabled || !url) {
615
+ addLog("debug", enabled ? "No server URL provided, skipping connection." : "Connection disabled via enabled flag.");
616
+ setState("discovering");
617
+ return () => {
618
+ isMountedRef.current = false;
619
+ };
620
+ }
621
+ addLog("debug", "useMcp mounted, initiating connection.");
622
+ connectAttemptRef.current = 0;
623
+ if (!authProviderRef.current || authProviderRef.current.serverUrl !== url) {
624
+ authProviderRef.current = new BrowserOAuthClientProvider(url, {
625
+ storageKeyPrefix,
626
+ clientName,
627
+ clientUri,
628
+ callbackUrl,
629
+ preventAutoAuth,
630
+ onPopupWindow
631
+ });
632
+ addLog("debug", "BrowserOAuthClientProvider initialized/updated on mount/option change.");
633
+ }
634
+ connect();
635
+ return () => {
636
+ isMountedRef.current = false;
637
+ addLog("debug", "useMcp unmounting, disconnecting.");
638
+ disconnect(true);
639
+ };
640
+ }, [url, enabled, storageKeyPrefix, callbackUrl, clientName, clientUri, clientConfig.name, clientConfig.version]);
641
+ useEffect(() => {
642
+ let retryTimeoutId = null;
643
+ if (state === "failed" && autoRetry && connectAttemptRef.current > 0) {
644
+ const delay = typeof autoRetry === "number" ? autoRetry : DEFAULT_RETRY_DELAY;
645
+ addLog("info", `Connection failed, auto-retrying in ${delay}ms...`);
646
+ retryTimeoutId = setTimeout(() => {
647
+ if (isMountedRef.current && stateRef.current === "failed") {
648
+ retry();
649
+ }
650
+ }, delay);
651
+ }
652
+ return () => {
653
+ if (retryTimeoutId) clearTimeout(retryTimeoutId);
654
+ };
655
+ }, [state, autoRetry, retry, addLog]);
656
+ return {
657
+ state,
658
+ tools,
659
+ resources,
660
+ resourceTemplates,
661
+ prompts,
662
+ error,
663
+ log,
664
+ authUrl,
665
+ callTool,
666
+ listResources,
667
+ readResource,
668
+ listPrompts,
669
+ getPrompt,
670
+ retry,
671
+ disconnect,
672
+ authenticate,
673
+ clearStorage
674
+ };
675
+ }
676
+ __name(useMcp, "useMcp");
677
+
678
+ export {
679
+ useMcp
680
+ };