mcp-use 0.2.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) 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 +5 -46
  23. package/dist/src/browser.d.ts.map +1 -1
  24. package/dist/src/browser.js +9 -75
  25. package/dist/src/oauth-helper.d.ts +2 -12
  26. package/dist/src/oauth-helper.d.ts.map +1 -1
  27. package/dist/src/react/index.cjs +986 -0
  28. package/dist/src/react/index.d.ts +9 -0
  29. package/dist/src/react/index.d.ts.map +1 -0
  30. package/dist/src/react/index.js +11 -0
  31. package/dist/src/react/types.d.ts +139 -0
  32. package/dist/src/react/types.d.ts.map +1 -0
  33. package/dist/src/react/useMcp.d.ts +3 -0
  34. package/dist/src/react/useMcp.d.ts.map +1 -0
  35. package/dist/src/server/index.cjs +566 -0
  36. package/dist/src/server/index.d.ts +3 -0
  37. package/dist/src/server/index.d.ts.map +1 -0
  38. package/dist/src/server/index.js +9 -0
  39. package/dist/src/server/logging.d.ts +16 -0
  40. package/dist/src/server/logging.d.ts.map +1 -0
  41. package/dist/src/server/mcp-server.d.ts +282 -0
  42. package/dist/src/server/mcp-server.d.ts.map +1 -0
  43. package/dist/src/server/types.d.ts +47 -0
  44. package/dist/src/server/types.d.ts.map +1 -0
  45. package/dist/src/utils/assert.d.ts +8 -0
  46. package/dist/src/utils/assert.d.ts.map +1 -0
  47. package/dist/tsconfig.tsbuildinfo +1 -0
  48. package/package.json +67 -40
  49. package/dist/src/adapters/base.js +0 -124
  50. package/dist/src/adapters/index.js +0 -2
  51. package/dist/src/adapters/langchain_adapter.js +0 -49
  52. package/dist/src/agents/base.js +0 -9
  53. package/dist/src/agents/index.js +0 -3
  54. package/dist/src/agents/mcp_agent.js +0 -1002
  55. package/dist/src/agents/prompts/system_prompt_builder.js +0 -40
  56. package/dist/src/agents/prompts/templates.js +0 -39
  57. package/dist/src/agents/remote.js +0 -264
  58. package/dist/src/agents/utils/ai_sdk.js +0 -62
  59. package/dist/src/agents/utils/index.js +0 -1
  60. package/dist/src/client/base.js +0 -119
  61. package/dist/src/client.js +0 -50
  62. package/dist/src/config.js +0 -34
  63. package/dist/src/connectors/base.js +0 -143
  64. package/dist/src/connectors/http.js +0 -150
  65. package/dist/src/connectors/index.js +0 -4
  66. package/dist/src/connectors/stdio.js +0 -68
  67. package/dist/src/connectors/websocket.js +0 -157
  68. package/dist/src/logging.js +0 -232
  69. package/dist/src/managers/index.js +0 -2
  70. package/dist/src/managers/server_manager.js +0 -106
  71. package/dist/src/managers/tools/acquire_active_mcp_server.js +0 -17
  72. package/dist/src/managers/tools/add_server_from_config.js +0 -40
  73. package/dist/src/managers/tools/base.js +0 -17
  74. package/dist/src/managers/tools/connect_mcp_server.js +0 -46
  75. package/dist/src/managers/tools/index.js +0 -5
  76. package/dist/src/managers/tools/list_mcp_servers.js +0 -33
  77. package/dist/src/managers/tools/release_mcp_server_connection.js +0 -19
  78. package/dist/src/oauth-helper.js +0 -427
  79. package/dist/src/observability/index.js +0 -12
  80. package/dist/src/observability/langfuse.js +0 -211
  81. package/dist/src/observability/manager.js +0 -199
  82. package/dist/src/observability/types.js +0 -4
  83. package/dist/src/session.js +0 -23
  84. package/dist/src/task_managers/base.js +0 -127
  85. package/dist/src/task_managers/index.js +0 -5
  86. package/dist/src/task_managers/sse.js +0 -43
  87. package/dist/src/task_managers/stdio.js +0 -51
  88. package/dist/src/task_managers/streamable_http.js +0 -50
  89. package/dist/src/task_managers/websocket.js +0 -67
  90. package/dist/src/telemetry/events.js +0 -44
  91. package/dist/src/telemetry/index.js +0 -8
  92. package/dist/src/telemetry/telemetry.js +0 -324
  93. package/dist/src/telemetry/utils.js +0 -39
  94. package/dist/tests/ai_sdk_compatibility.test.js +0 -214
  95. package/dist/tests/stream_events.test.js +0 -307
  96. package/dist/tests/stream_events_simple.test.js +0 -179
  97. package/dist/vitest.config.js +0 -21
@@ -0,0 +1,986 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
20
+
21
+ // src/react/index.ts
22
+ var react_exports = {};
23
+ __export(react_exports, {
24
+ onMcpAuthorization: () => onMcpAuthorization,
25
+ useMcp: () => useMcp
26
+ });
27
+ module.exports = __toCommonJS(react_exports);
28
+
29
+ // src/react/useMcp.ts
30
+ var import_types = require("@modelcontextprotocol/sdk/types.js");
31
+ var import_react = require("react");
32
+ var import_sse = require("@modelcontextprotocol/sdk/client/sse.js");
33
+ var import_streamableHttp = require("@modelcontextprotocol/sdk/client/streamableHttp.js");
34
+ var import_client = require("@modelcontextprotocol/sdk/client/index.js");
35
+ var import_auth = require("@modelcontextprotocol/sdk/client/auth.js");
36
+ var import_strict_url_sanitise2 = require("strict-url-sanitise");
37
+
38
+ // src/auth/browser-provider.ts
39
+ var import_strict_url_sanitise = require("strict-url-sanitise");
40
+ var BrowserOAuthClientProvider = class {
41
+ static {
42
+ __name(this, "BrowserOAuthClientProvider");
43
+ }
44
+ serverUrl;
45
+ storageKeyPrefix;
46
+ serverUrlHash;
47
+ clientName;
48
+ clientUri;
49
+ callbackUrl;
50
+ preventAutoAuth;
51
+ onPopupWindow;
52
+ constructor(serverUrl, options = {}) {
53
+ this.serverUrl = serverUrl;
54
+ this.storageKeyPrefix = options.storageKeyPrefix || "mcp:auth";
55
+ this.serverUrlHash = this.hashString(serverUrl);
56
+ this.clientName = options.clientName || "MCP Browser Client";
57
+ this.clientUri = options.clientUri || (typeof window !== "undefined" ? window.location.origin : "");
58
+ this.callbackUrl = (0, import_strict_url_sanitise.sanitizeUrl)(
59
+ options.callbackUrl || (typeof window !== "undefined" ? new URL("/oauth/callback", window.location.origin).toString() : "/oauth/callback")
60
+ );
61
+ this.preventAutoAuth = options.preventAutoAuth;
62
+ this.onPopupWindow = options.onPopupWindow;
63
+ }
64
+ // --- SDK Interface Methods ---
65
+ get redirectUrl() {
66
+ return (0, import_strict_url_sanitise.sanitizeUrl)(this.callbackUrl);
67
+ }
68
+ get clientMetadata() {
69
+ return {
70
+ redirect_uris: [this.redirectUrl],
71
+ token_endpoint_auth_method: "none",
72
+ // Public client
73
+ grant_types: ["authorization_code", "refresh_token"],
74
+ response_types: ["code"],
75
+ client_name: this.clientName,
76
+ client_uri: this.clientUri
77
+ // scope: 'openid profile email mcp', // Example scopes, adjust as needed
78
+ };
79
+ }
80
+ async clientInformation() {
81
+ const key = this.getKey("client_info");
82
+ const data = localStorage.getItem(key);
83
+ if (!data) return void 0;
84
+ try {
85
+ return JSON.parse(data);
86
+ } catch (e) {
87
+ console.warn(`[${this.storageKeyPrefix}] Failed to parse client information:`, e);
88
+ localStorage.removeItem(key);
89
+ return void 0;
90
+ }
91
+ }
92
+ // NOTE: The SDK's auth() function uses this if dynamic registration is needed.
93
+ // Ensure your OAuthClientInformationFull matches the expected structure if DCR is used.
94
+ async saveClientInformation(clientInformation) {
95
+ const key = this.getKey("client_info");
96
+ localStorage.setItem(key, JSON.stringify(clientInformation));
97
+ }
98
+ async tokens() {
99
+ const key = this.getKey("tokens");
100
+ const data = localStorage.getItem(key);
101
+ if (!data) return void 0;
102
+ try {
103
+ return JSON.parse(data);
104
+ } catch (e) {
105
+ console.warn(`[${this.storageKeyPrefix}] Failed to parse tokens:`, e);
106
+ localStorage.removeItem(key);
107
+ return void 0;
108
+ }
109
+ }
110
+ async saveTokens(tokens) {
111
+ const key = this.getKey("tokens");
112
+ localStorage.setItem(key, JSON.stringify(tokens));
113
+ localStorage.removeItem(this.getKey("code_verifier"));
114
+ localStorage.removeItem(this.getKey("last_auth_url"));
115
+ }
116
+ async saveCodeVerifier(codeVerifier) {
117
+ const key = this.getKey("code_verifier");
118
+ localStorage.setItem(key, codeVerifier);
119
+ }
120
+ async codeVerifier() {
121
+ const key = this.getKey("code_verifier");
122
+ const verifier = localStorage.getItem(key);
123
+ if (!verifier) {
124
+ throw new Error(
125
+ `[${this.storageKeyPrefix}] Code verifier not found in storage for key ${key}. Auth flow likely corrupted or timed out.`
126
+ );
127
+ }
128
+ return verifier;
129
+ }
130
+ /**
131
+ * Generates and stores the authorization URL with state, without opening a popup.
132
+ * Used when preventAutoAuth is enabled to provide the URL for manual navigation.
133
+ * @param authorizationUrl The fully constructed authorization URL from the SDK.
134
+ * @returns The full authorization URL with state parameter.
135
+ */
136
+ async prepareAuthorizationUrl(authorizationUrl) {
137
+ const state = globalThis.crypto.randomUUID();
138
+ const stateKey = `${this.storageKeyPrefix}:state_${state}`;
139
+ const stateData = {
140
+ serverUrlHash: this.serverUrlHash,
141
+ expiry: Date.now() + 1e3 * 60 * 10,
142
+ // State expires in 10 minutes
143
+ // Store provider options needed to reconstruct on callback
144
+ providerOptions: {
145
+ serverUrl: this.serverUrl,
146
+ storageKeyPrefix: this.storageKeyPrefix,
147
+ clientName: this.clientName,
148
+ clientUri: this.clientUri,
149
+ callbackUrl: this.callbackUrl
150
+ }
151
+ };
152
+ localStorage.setItem(stateKey, JSON.stringify(stateData));
153
+ authorizationUrl.searchParams.set("state", state);
154
+ const authUrlString = authorizationUrl.toString();
155
+ const sanitizedAuthUrl = (0, import_strict_url_sanitise.sanitizeUrl)(authUrlString);
156
+ localStorage.setItem(this.getKey("last_auth_url"), sanitizedAuthUrl);
157
+ return sanitizedAuthUrl;
158
+ }
159
+ /**
160
+ * Redirects the user agent to the authorization URL, storing necessary state.
161
+ * This now adheres to the SDK's void return type expectation for the interface.
162
+ * @param authorizationUrl The fully constructed authorization URL from the SDK.
163
+ */
164
+ async redirectToAuthorization(authorizationUrl) {
165
+ if (this.preventAutoAuth) return;
166
+ const sanitizedAuthUrl = await this.prepareAuthorizationUrl(authorizationUrl);
167
+ const popupFeatures = "width=600,height=700,resizable=yes,scrollbars=yes,status=yes";
168
+ try {
169
+ const popup = window.open(sanitizedAuthUrl, `mcp_auth_${this.serverUrlHash}`, popupFeatures);
170
+ if (this.onPopupWindow) {
171
+ this.onPopupWindow(sanitizedAuthUrl, popupFeatures, popup);
172
+ }
173
+ if (!popup || popup.closed || typeof popup.closed === "undefined") {
174
+ console.warn(
175
+ `[${this.storageKeyPrefix}] Popup likely blocked by browser. Manual navigation might be required using the stored URL.`
176
+ );
177
+ } else {
178
+ popup.focus();
179
+ console.info(`[${this.storageKeyPrefix}] Redirecting to authorization URL in popup.`);
180
+ }
181
+ } catch (e) {
182
+ console.error(`[${this.storageKeyPrefix}] Error opening popup window:`, e);
183
+ }
184
+ }
185
+ // --- Helper Methods ---
186
+ /**
187
+ * Retrieves the last URL passed to `redirectToAuthorization`. Useful for manual fallback.
188
+ */
189
+ getLastAttemptedAuthUrl() {
190
+ const storedUrl = localStorage.getItem(this.getKey("last_auth_url"));
191
+ return storedUrl ? (0, import_strict_url_sanitise.sanitizeUrl)(storedUrl) : null;
192
+ }
193
+ clearStorage() {
194
+ const prefixPattern = `${this.storageKeyPrefix}_${this.serverUrlHash}_`;
195
+ const statePattern = `${this.storageKeyPrefix}:state_`;
196
+ const keysToRemove = [];
197
+ let count = 0;
198
+ for (let i = 0; i < localStorage.length; i++) {
199
+ const key = localStorage.key(i);
200
+ if (!key) continue;
201
+ if (key.startsWith(prefixPattern)) {
202
+ keysToRemove.push(key);
203
+ } else if (key.startsWith(statePattern)) {
204
+ try {
205
+ const item = localStorage.getItem(key);
206
+ if (item) {
207
+ const state = JSON.parse(item);
208
+ if (state.serverUrlHash === this.serverUrlHash) {
209
+ keysToRemove.push(key);
210
+ }
211
+ }
212
+ } catch (e) {
213
+ console.warn(`[${this.storageKeyPrefix}] Error parsing state key ${key} during clearStorage:`, e);
214
+ }
215
+ }
216
+ }
217
+ const uniqueKeysToRemove = [...new Set(keysToRemove)];
218
+ uniqueKeysToRemove.forEach((key) => {
219
+ localStorage.removeItem(key);
220
+ count++;
221
+ });
222
+ return count;
223
+ }
224
+ hashString(str) {
225
+ let hash = 0;
226
+ for (let i = 0; i < str.length; i++) {
227
+ const char = str.charCodeAt(i);
228
+ hash = (hash << 5) - hash + char;
229
+ hash = hash & hash;
230
+ }
231
+ return Math.abs(hash).toString(16);
232
+ }
233
+ getKey(keySuffix) {
234
+ return `${this.storageKeyPrefix}_${this.serverUrlHash}_${keySuffix}`;
235
+ }
236
+ };
237
+
238
+ // src/utils/assert.ts
239
+ function assert(condition, message) {
240
+ if (!condition) {
241
+ throw new Error(message);
242
+ }
243
+ }
244
+ __name(assert, "assert");
245
+
246
+ // src/react/useMcp.ts
247
+ var DEFAULT_RECONNECT_DELAY = 3e3;
248
+ var DEFAULT_RETRY_DELAY = 5e3;
249
+ var AUTH_TIMEOUT = 5 * 60 * 1e3;
250
+ function useMcp(options) {
251
+ const {
252
+ url,
253
+ enabled = true,
254
+ clientName,
255
+ clientUri,
256
+ callbackUrl = typeof window !== "undefined" ? (0, import_strict_url_sanitise2.sanitizeUrl)(new URL("/oauth/callback", window.location.origin).toString()) : "/oauth/callback",
257
+ storageKeyPrefix = "mcp:auth",
258
+ clientConfig = {},
259
+ customHeaders = {},
260
+ debug: _debug = false,
261
+ autoRetry = false,
262
+ autoReconnect = DEFAULT_RECONNECT_DELAY,
263
+ transportType = "auto",
264
+ preventAutoAuth = false,
265
+ onPopupWindow
266
+ } = options;
267
+ const [state, setState] = (0, import_react.useState)("discovering");
268
+ const [tools, setTools] = (0, import_react.useState)([]);
269
+ const [resources, setResources] = (0, import_react.useState)([]);
270
+ const [resourceTemplates, setResourceTemplates] = (0, import_react.useState)([]);
271
+ const [prompts, setPrompts] = (0, import_react.useState)([]);
272
+ const [error, setError] = (0, import_react.useState)(void 0);
273
+ const [log, setLog] = (0, import_react.useState)([]);
274
+ const [authUrl, setAuthUrl] = (0, import_react.useState)(void 0);
275
+ const clientRef = (0, import_react.useRef)(null);
276
+ const transportRef = (0, import_react.useRef)(null);
277
+ const authProviderRef = (0, import_react.useRef)(null);
278
+ const connectingRef = (0, import_react.useRef)(false);
279
+ const isMountedRef = (0, import_react.useRef)(true);
280
+ const connectAttemptRef = (0, import_react.useRef)(0);
281
+ const authTimeoutRef = (0, import_react.useRef)(null);
282
+ const stateRef = (0, import_react.useRef)(state);
283
+ const autoReconnectRef = (0, import_react.useRef)(autoReconnect);
284
+ const successfulTransportRef = (0, import_react.useRef)(null);
285
+ (0, import_react.useEffect)(() => {
286
+ stateRef.current = state;
287
+ autoReconnectRef.current = autoReconnect;
288
+ }, [state, autoReconnect]);
289
+ const addLog = (0, import_react.useCallback)(
290
+ (level, message, ...args) => {
291
+ const fullMessage = args.length > 0 ? `${message} ${args.map((arg) => JSON.stringify(arg)).join(" ")}` : message;
292
+ console[level](`[useMcp] ${fullMessage}`);
293
+ if (isMountedRef.current) {
294
+ setLog((prevLog) => [...prevLog.slice(-100), { level, message: fullMessage, timestamp: Date.now() }]);
295
+ }
296
+ },
297
+ []
298
+ );
299
+ const disconnect = (0, import_react.useCallback)(
300
+ async (quiet = false) => {
301
+ if (!quiet) addLog("info", "Disconnecting...");
302
+ connectingRef.current = false;
303
+ if (authTimeoutRef.current) clearTimeout(authTimeoutRef.current);
304
+ authTimeoutRef.current = null;
305
+ const transport = transportRef.current;
306
+ clientRef.current = null;
307
+ transportRef.current = null;
308
+ if (isMountedRef.current && !quiet) {
309
+ setState("discovering");
310
+ setTools([]);
311
+ setResources([]);
312
+ setResourceTemplates([]);
313
+ setPrompts([]);
314
+ setError(void 0);
315
+ setAuthUrl(void 0);
316
+ }
317
+ if (transport) {
318
+ try {
319
+ await transport.close();
320
+ if (!quiet) addLog("debug", "Transport closed");
321
+ } catch (err) {
322
+ if (!quiet) addLog("warn", "Error closing transport:", err);
323
+ }
324
+ }
325
+ },
326
+ [addLog]
327
+ );
328
+ const failConnection = (0, import_react.useCallback)(
329
+ (errorMessage, connectionError) => {
330
+ addLog("error", errorMessage, connectionError ?? "");
331
+ if (isMountedRef.current) {
332
+ setState("failed");
333
+ setError(errorMessage);
334
+ const manualUrl = authProviderRef.current?.getLastAttemptedAuthUrl();
335
+ if (manualUrl) {
336
+ setAuthUrl(manualUrl);
337
+ addLog("info", "Manual authentication URL may be available.", manualUrl);
338
+ }
339
+ }
340
+ connectingRef.current = false;
341
+ },
342
+ [addLog]
343
+ );
344
+ const connect = (0, import_react.useCallback)(async () => {
345
+ if (!enabled || !url) {
346
+ addLog("debug", enabled ? "No server URL provided, skipping connection." : "Connection disabled via enabled flag.");
347
+ return;
348
+ }
349
+ if (connectingRef.current) {
350
+ addLog("debug", "Connection attempt already in progress.");
351
+ return;
352
+ }
353
+ if (!isMountedRef.current) {
354
+ addLog("debug", "Connect called after unmount, aborting.");
355
+ return;
356
+ }
357
+ connectingRef.current = true;
358
+ connectAttemptRef.current += 1;
359
+ setError(void 0);
360
+ setAuthUrl(void 0);
361
+ successfulTransportRef.current = null;
362
+ setState("discovering");
363
+ addLog("info", `Connecting attempt #${connectAttemptRef.current} to ${url}...`);
364
+ if (!authProviderRef.current) {
365
+ authProviderRef.current = new BrowserOAuthClientProvider(url, {
366
+ storageKeyPrefix,
367
+ clientName,
368
+ clientUri,
369
+ callbackUrl,
370
+ preventAutoAuth,
371
+ onPopupWindow
372
+ });
373
+ addLog("debug", "BrowserOAuthClientProvider initialized in connect.");
374
+ }
375
+ if (!clientRef.current) {
376
+ clientRef.current = new import_client.Client(
377
+ { name: clientConfig.name || "use-mcp-react-client", version: clientConfig.version || "0.1.0" },
378
+ { capabilities: {} }
379
+ );
380
+ addLog("debug", "MCP Client initialized in connect.");
381
+ }
382
+ const tryConnectWithTransport = /* @__PURE__ */ __name(async (transportTypeParam, isAuthRetry = false) => {
383
+ addLog("info", `Attempting connection with ${transportTypeParam.toUpperCase()} transport${isAuthRetry ? " (after auth)" : ""}...`);
384
+ if (stateRef.current !== "authenticating") {
385
+ setState("connecting");
386
+ }
387
+ let transportInstance;
388
+ try {
389
+ assert(authProviderRef.current, "Auth Provider must be initialized");
390
+ assert(clientRef.current, "Client must be initialized");
391
+ if (transportRef.current) {
392
+ await transportRef.current.close().catch((e) => addLog("warn", `Error closing previous transport: ${e.message}`));
393
+ transportRef.current = null;
394
+ }
395
+ const commonOptions = {
396
+ authProvider: authProviderRef.current,
397
+ requestInit: {
398
+ headers: {
399
+ Accept: "application/json, text/event-stream",
400
+ ...customHeaders
401
+ }
402
+ }
403
+ };
404
+ const sanitizedUrl = (0, import_strict_url_sanitise2.sanitizeUrl)(url);
405
+ const targetUrl = new URL(sanitizedUrl);
406
+ addLog("debug", `Creating ${transportTypeParam.toUpperCase()} transport for URL: ${targetUrl.toString()}`);
407
+ if (transportTypeParam === "http") {
408
+ addLog("debug", "Creating StreamableHTTPClientTransport...");
409
+ transportInstance = new import_streamableHttp.StreamableHTTPClientTransport(targetUrl, commonOptions);
410
+ addLog("debug", "StreamableHTTPClientTransport created successfully");
411
+ } else {
412
+ addLog("debug", "Creating SSEClientTransport...");
413
+ transportInstance = new import_sse.SSEClientTransport(targetUrl, commonOptions);
414
+ addLog("debug", "SSEClientTransport created successfully");
415
+ }
416
+ transportRef.current = transportInstance;
417
+ addLog("debug", `${transportTypeParam.toUpperCase()} transport created and assigned to ref.`);
418
+ } catch (err) {
419
+ failConnection(
420
+ `Failed to create ${transportTypeParam.toUpperCase()} transport: ${err instanceof Error ? err.message : String(err)}`,
421
+ err instanceof Error ? err : void 0
422
+ );
423
+ return "failed";
424
+ }
425
+ transportInstance.onmessage = (message) => {
426
+ addLog("debug", `[Transport] Received: ${JSON.stringify(message)}`);
427
+ clientRef.current?.handleMessage?.(message);
428
+ };
429
+ transportInstance.onerror = (err) => {
430
+ addLog("warn", `Transport error event (${transportTypeParam.toUpperCase()}):`, err);
431
+ failConnection(`Transport error (${transportTypeParam.toUpperCase()}): ${err.message}`, err);
432
+ };
433
+ transportInstance.onclose = () => {
434
+ if (!isMountedRef.current || connectingRef.current) return;
435
+ addLog("info", `Transport connection closed (${successfulTransportRef.current || "unknown"} type).`);
436
+ const currentState = stateRef.current;
437
+ const currentAutoReconnect = autoReconnectRef.current;
438
+ if (currentState === "ready" && currentAutoReconnect) {
439
+ const delay = typeof currentAutoReconnect === "number" ? currentAutoReconnect : DEFAULT_RECONNECT_DELAY;
440
+ addLog("info", `Attempting to reconnect in ${delay}ms...`);
441
+ setState("connecting");
442
+ setTimeout(() => {
443
+ if (isMountedRef.current) {
444
+ connect();
445
+ }
446
+ }, delay);
447
+ } else if (currentState !== "failed" && currentState !== "authenticating") {
448
+ failConnection("Connection closed unexpectedly.");
449
+ }
450
+ };
451
+ try {
452
+ addLog("info", `Connecting client via ${transportTypeParam.toUpperCase()}...`);
453
+ await clientRef.current.connect(transportInstance);
454
+ addLog("info", `Client connected via ${transportTypeParam.toUpperCase()}. Loading tools, resources, and prompts...`);
455
+ successfulTransportRef.current = transportTypeParam;
456
+ setState("loading");
457
+ const toolsResponse = await clientRef.current.request({ method: "tools/list" }, import_types.ListToolsResultSchema);
458
+ let resourcesResponse = { resources: [], resourceTemplates: [] };
459
+ try {
460
+ resourcesResponse = await clientRef.current.request({ method: "resources/list" }, import_types.ListResourcesResultSchema);
461
+ } catch (err) {
462
+ addLog("debug", "Server does not support resources/list method", err);
463
+ }
464
+ let promptsResponse = { prompts: [] };
465
+ try {
466
+ promptsResponse = await clientRef.current.request({ method: "prompts/list" }, import_types.ListPromptsResultSchema);
467
+ } catch (err) {
468
+ addLog("debug", "Server does not support prompts/list method", err);
469
+ }
470
+ if (isMountedRef.current) {
471
+ setTools(toolsResponse.tools);
472
+ setResources(resourcesResponse.resources);
473
+ setResourceTemplates(Array.isArray(resourcesResponse.resourceTemplates) ? resourcesResponse.resourceTemplates : []);
474
+ setPrompts(promptsResponse.prompts);
475
+ const summary = [`Loaded ${toolsResponse.tools.length} tools`];
476
+ if (resourcesResponse.resources.length > 0 || resourcesResponse.resourceTemplates && resourcesResponse.resourceTemplates.length > 0) {
477
+ summary.push(`${resourcesResponse.resources.length} resources`);
478
+ if (Array.isArray(resourcesResponse.resourceTemplates) && resourcesResponse.resourceTemplates.length > 0) {
479
+ summary.push(`${resourcesResponse.resourceTemplates.length} resource templates`);
480
+ }
481
+ }
482
+ if (promptsResponse.prompts.length > 0) {
483
+ summary.push(`${promptsResponse.prompts.length} prompts`);
484
+ }
485
+ addLog("info", summary.join(", ") + ".");
486
+ setState("ready");
487
+ connectAttemptRef.current = 0;
488
+ return "success";
489
+ } else {
490
+ return "failed";
491
+ }
492
+ } catch (connectErr) {
493
+ addLog("debug", `Client connect error via ${transportTypeParam.toUpperCase()}:`, connectErr);
494
+ const errorInstance = connectErr instanceof Error ? connectErr : new Error(String(connectErr));
495
+ const errorMessage = errorInstance.message;
496
+ const is404 = errorMessage.includes("404") || errorMessage.includes("Not Found");
497
+ const is405 = errorMessage.includes("405") || errorMessage.includes("Method Not Allowed");
498
+ const isLikelyCors = errorMessage === "Failed to fetch" || errorMessage === "NetworkError when attempting to fetch resource." || errorMessage === "Load failed";
499
+ if (transportTypeParam === "http" && (is404 || is405 || isLikelyCors)) {
500
+ addLog("warn", `HTTP transport failed (${isLikelyCors ? "CORS" : is404 ? "404" : "405"}), will try fallback.`);
501
+ return "fallback";
502
+ }
503
+ if (errorInstance instanceof import_auth.UnauthorizedError || errorMessage.includes("Unauthorized") || errorMessage.includes("401")) {
504
+ if (isAuthRetry) {
505
+ addLog("error", "Authentication failed even after successful token refresh. This may indicate a server issue.");
506
+ failConnection("Authentication loop detected - auth succeeded but connection still unauthorized.");
507
+ return "failed";
508
+ }
509
+ addLog("info", "Authentication required.");
510
+ assert(authProviderRef.current, "Auth Provider not available for auth flow");
511
+ const existingTokens = await authProviderRef.current.tokens();
512
+ if (preventAutoAuth && !existingTokens) {
513
+ addLog("info", "Authentication required but auto-auth prevented. User action needed.");
514
+ setState("pending_auth");
515
+ return "auth_redirect";
516
+ }
517
+ if (stateRef.current !== "authenticating" && stateRef.current !== "pending_auth") {
518
+ setState("authenticating");
519
+ if (authTimeoutRef.current) clearTimeout(authTimeoutRef.current);
520
+ authTimeoutRef.current = setTimeout(() => {
521
+ if (isMountedRef.current) {
522
+ const currentState = stateRef.current;
523
+ if (currentState === "authenticating") {
524
+ failConnection("Authentication timed out. Please try again.");
525
+ }
526
+ }
527
+ }, AUTH_TIMEOUT);
528
+ }
529
+ try {
530
+ assert(url, "Server URL is required for authentication");
531
+ const authResult = await (0, import_auth.auth)(authProviderRef.current, { serverUrl: url });
532
+ if (!isMountedRef.current) return "failed";
533
+ if (authResult === "AUTHORIZED") {
534
+ addLog("info", "Authentication successful via existing token or refresh. Retrying transport connection...");
535
+ if (authTimeoutRef.current) clearTimeout(authTimeoutRef.current);
536
+ authTimeoutRef.current = null;
537
+ return await tryConnectWithTransport(transportTypeParam, true);
538
+ } else if (authResult === "REDIRECT") {
539
+ addLog("info", "Redirecting for authentication. Waiting for callback...");
540
+ return "auth_redirect";
541
+ }
542
+ } catch (sdkAuthError) {
543
+ if (!isMountedRef.current) return "failed";
544
+ if (authTimeoutRef.current) clearTimeout(authTimeoutRef.current);
545
+ failConnection(
546
+ `Failed to initiate authentication: ${sdkAuthError instanceof Error ? sdkAuthError.message : String(sdkAuthError)}`,
547
+ sdkAuthError instanceof Error ? sdkAuthError : void 0
548
+ );
549
+ return "failed";
550
+ }
551
+ }
552
+ failConnection(`Failed to connect via ${transportTypeParam.toUpperCase()}: ${errorMessage}`, errorInstance);
553
+ return "failed";
554
+ }
555
+ }, "tryConnectWithTransport");
556
+ let finalStatus = "failed";
557
+ if (transportType === "sse") {
558
+ addLog("debug", "Using SSE-only transport mode");
559
+ finalStatus = await tryConnectWithTransport("sse");
560
+ } else if (transportType === "http") {
561
+ addLog("debug", "Using HTTP-only transport mode");
562
+ finalStatus = await tryConnectWithTransport("http");
563
+ } else {
564
+ addLog("debug", "Using auto transport mode (HTTP with SSE fallback)");
565
+ const httpResult = await tryConnectWithTransport("http");
566
+ if (httpResult === "fallback" && isMountedRef.current && stateRef.current !== "authenticating") {
567
+ addLog("info", "HTTP failed, attempting SSE fallback...");
568
+ const sseResult = await tryConnectWithTransport("sse");
569
+ finalStatus = sseResult;
570
+ } else {
571
+ finalStatus = httpResult;
572
+ }
573
+ }
574
+ if (finalStatus === "success" || finalStatus === "failed") {
575
+ connectingRef.current = false;
576
+ }
577
+ addLog("debug", `Connection sequence finished with status: ${finalStatus}`);
578
+ }, [
579
+ addLog,
580
+ failConnection,
581
+ disconnect,
582
+ url,
583
+ storageKeyPrefix,
584
+ clientName,
585
+ clientUri,
586
+ callbackUrl,
587
+ clientConfig.name,
588
+ clientConfig.version,
589
+ customHeaders,
590
+ transportType,
591
+ preventAutoAuth,
592
+ onPopupWindow,
593
+ enabled
594
+ ]);
595
+ const callTool = (0, import_react.useCallback)(
596
+ async (name, args) => {
597
+ if (stateRef.current !== "ready" || !clientRef.current) {
598
+ throw new Error(`MCP client is not ready (current state: ${state}). Cannot call tool "${name}".`);
599
+ }
600
+ addLog("info", `Calling tool: ${name}`, args);
601
+ try {
602
+ const result = await clientRef.current.request({ method: "tools/call", params: { name, arguments: args } }, import_types.CallToolResultSchema);
603
+ addLog("info", `Tool "${name}" call successful:`, result);
604
+ return result;
605
+ } catch (err) {
606
+ addLog("error", `Error calling tool "${name}": ${err instanceof Error ? err.message : String(err)}`, err);
607
+ const errorInstance = err instanceof Error ? err : new Error(String(err));
608
+ if (errorInstance instanceof import_auth.UnauthorizedError || errorInstance.message.includes("Unauthorized") || errorInstance.message.includes("401")) {
609
+ addLog("warn", "Tool call unauthorized, attempting re-authentication...");
610
+ setState("authenticating");
611
+ if (authTimeoutRef.current) clearTimeout(authTimeoutRef.current);
612
+ authTimeoutRef.current = setTimeout(() => {
613
+ if (isMountedRef.current) {
614
+ const currentState2 = stateRef.current;
615
+ if (currentState2 === "authenticating") {
616
+ failConnection("Authentication timed out. Please try again.");
617
+ }
618
+ }
619
+ }, AUTH_TIMEOUT);
620
+ try {
621
+ assert(authProviderRef.current, "Auth Provider not available for tool re-auth");
622
+ assert(url, "Server URL is required for authentication");
623
+ const authResult = await (0, import_auth.auth)(authProviderRef.current, { serverUrl: url });
624
+ if (!isMountedRef.current) return;
625
+ if (authResult === "AUTHORIZED") {
626
+ addLog("info", "Re-authentication successful. Retrying tool call is recommended, or reconnecting.");
627
+ if (authTimeoutRef.current) clearTimeout(authTimeoutRef.current);
628
+ connectingRef.current = false;
629
+ connect();
630
+ } else if (authResult === "REDIRECT") {
631
+ addLog("info", "Redirecting for re-authentication for tool call.");
632
+ }
633
+ } catch (sdkAuthError) {
634
+ if (!isMountedRef.current) return;
635
+ if (authTimeoutRef.current) clearTimeout(authTimeoutRef.current);
636
+ failConnection(
637
+ `Re-authentication failed: ${sdkAuthError instanceof Error ? sdkAuthError.message : String(sdkAuthError)}`,
638
+ sdkAuthError instanceof Error ? sdkAuthError : void 0
639
+ );
640
+ }
641
+ }
642
+ const currentState = stateRef.current;
643
+ if (currentState !== "authenticating") {
644
+ throw err;
645
+ }
646
+ return void 0;
647
+ }
648
+ },
649
+ [state, url, addLog, failConnection, connect]
650
+ );
651
+ const retry = (0, import_react.useCallback)(() => {
652
+ if (stateRef.current === "failed") {
653
+ addLog("info", "Retry requested...");
654
+ connect();
655
+ } else {
656
+ addLog("warn", `Retry called but state is not 'failed' (state: ${stateRef.current}). Ignoring.`);
657
+ }
658
+ }, [addLog, connect]);
659
+ const authenticate = (0, import_react.useCallback)(async () => {
660
+ addLog("info", "Manual authentication requested...");
661
+ const currentState = stateRef.current;
662
+ if (currentState === "failed") {
663
+ addLog("info", "Attempting to reconnect and authenticate via retry...");
664
+ retry();
665
+ } else if (currentState === "pending_auth") {
666
+ addLog("info", "Proceeding with authentication from pending state...");
667
+ setState("authenticating");
668
+ if (authTimeoutRef.current) clearTimeout(authTimeoutRef.current);
669
+ authTimeoutRef.current = setTimeout(() => {
670
+ if (isMountedRef.current) {
671
+ const currentStateValue = stateRef.current;
672
+ if (currentStateValue === "authenticating") {
673
+ failConnection("Authentication timed out. Please try again.");
674
+ }
675
+ }
676
+ }, AUTH_TIMEOUT);
677
+ try {
678
+ assert(authProviderRef.current, "Auth Provider not available for manual auth");
679
+ assert(url, "Server URL is required for authentication");
680
+ const authResult = await (0, import_auth.auth)(authProviderRef.current, { serverUrl: url });
681
+ if (!isMountedRef.current) return;
682
+ if (authResult === "AUTHORIZED") {
683
+ addLog("info", "Manual authentication successful. Re-attempting connection...");
684
+ if (authTimeoutRef.current) clearTimeout(authTimeoutRef.current);
685
+ connectingRef.current = false;
686
+ connect();
687
+ } else if (authResult === "REDIRECT") {
688
+ addLog("info", "Redirecting for manual authentication. Waiting for callback...");
689
+ }
690
+ } catch (authError) {
691
+ if (!isMountedRef.current) return;
692
+ if (authTimeoutRef.current) clearTimeout(authTimeoutRef.current);
693
+ failConnection(
694
+ `Manual authentication failed: ${authError instanceof Error ? authError.message : String(authError)}`,
695
+ authError instanceof Error ? authError : void 0
696
+ );
697
+ }
698
+ } else if (currentState === "authenticating") {
699
+ addLog("warn", "Already attempting authentication. Check for blocked popups or wait for timeout.");
700
+ const manualUrl = authProviderRef.current?.getLastAttemptedAuthUrl();
701
+ if (manualUrl && !authUrl) {
702
+ setAuthUrl(manualUrl);
703
+ addLog("info", "Manual authentication URL retrieved:", manualUrl);
704
+ }
705
+ } else {
706
+ addLog(
707
+ "info",
708
+ `Client not in a state requiring manual authentication trigger (state: ${currentState}). If needed, try disconnecting and reconnecting.`
709
+ );
710
+ }
711
+ }, [addLog, retry, authUrl, url, failConnection, connect]);
712
+ const clearStorage = (0, import_react.useCallback)(() => {
713
+ if (authProviderRef.current) {
714
+ const count = authProviderRef.current.clearStorage();
715
+ addLog("info", `Cleared ${count} item(s) from localStorage for ${url}.`);
716
+ setAuthUrl(void 0);
717
+ disconnect();
718
+ } else {
719
+ addLog("warn", "Auth provider not initialized, cannot clear storage.");
720
+ }
721
+ }, [url, addLog, disconnect]);
722
+ const listResources = (0, import_react.useCallback)(async () => {
723
+ if (stateRef.current !== "ready" || !clientRef.current) {
724
+ throw new Error(`MCP client is not ready (current state: ${state}). Cannot list resources.`);
725
+ }
726
+ addLog("info", "Listing resources...");
727
+ try {
728
+ const resourcesResponse = await clientRef.current.request({ method: "resources/list" }, import_types.ListResourcesResultSchema);
729
+ if (isMountedRef.current) {
730
+ setResources(resourcesResponse.resources);
731
+ setResourceTemplates(Array.isArray(resourcesResponse.resourceTemplates) ? resourcesResponse.resourceTemplates : []);
732
+ addLog(
733
+ "info",
734
+ `Listed ${resourcesResponse.resources.length} resources, ${Array.isArray(resourcesResponse.resourceTemplates) ? resourcesResponse.resourceTemplates.length : 0} resource templates.`
735
+ );
736
+ }
737
+ } catch (err) {
738
+ addLog("error", `Error listing resources: ${err instanceof Error ? err.message : String(err)}`, err);
739
+ throw err;
740
+ }
741
+ }, [state, addLog]);
742
+ const readResource = (0, import_react.useCallback)(
743
+ async (uri) => {
744
+ if (stateRef.current !== "ready" || !clientRef.current) {
745
+ throw new Error(`MCP client is not ready (current state: ${state}). Cannot read resource "${uri}".`);
746
+ }
747
+ addLog("info", `Reading resource: ${uri}`);
748
+ try {
749
+ const result = await clientRef.current.request({ method: "resources/read", params: { uri } }, import_types.ReadResourceResultSchema);
750
+ addLog("info", `Resource "${uri}" read successfully`);
751
+ return result;
752
+ } catch (err) {
753
+ addLog("error", `Error reading resource "${uri}": ${err instanceof Error ? err.message : String(err)}`, err);
754
+ throw err;
755
+ }
756
+ },
757
+ [state, addLog]
758
+ );
759
+ const listPrompts = (0, import_react.useCallback)(async () => {
760
+ if (stateRef.current !== "ready" || !clientRef.current) {
761
+ throw new Error(`MCP client is not ready (current state: ${state}). Cannot list prompts.`);
762
+ }
763
+ addLog("info", "Listing prompts...");
764
+ try {
765
+ const promptsResponse = await clientRef.current.request({ method: "prompts/list" }, import_types.ListPromptsResultSchema);
766
+ if (isMountedRef.current) {
767
+ setPrompts(promptsResponse.prompts);
768
+ addLog("info", `Listed ${promptsResponse.prompts.length} prompts.`);
769
+ }
770
+ } catch (err) {
771
+ addLog("error", `Error listing prompts: ${err instanceof Error ? err.message : String(err)}`, err);
772
+ throw err;
773
+ }
774
+ }, [state, addLog]);
775
+ const getPrompt = (0, import_react.useCallback)(
776
+ async (name, args) => {
777
+ if (stateRef.current !== "ready" || !clientRef.current) {
778
+ throw new Error(`MCP client is not ready (current state: ${state}). Cannot get prompt "${name}".`);
779
+ }
780
+ addLog("info", `Getting prompt: ${name}`, args);
781
+ try {
782
+ const result = await clientRef.current.request({ method: "prompts/get", params: { name, arguments: args } }, import_types.GetPromptResultSchema);
783
+ addLog("info", `Prompt "${name}" retrieved successfully`);
784
+ return result;
785
+ } catch (err) {
786
+ addLog("error", `Error getting prompt "${name}": ${err instanceof Error ? err.message : String(err)}`, err);
787
+ throw err;
788
+ }
789
+ },
790
+ [state, addLog]
791
+ );
792
+ const connectRef = (0, import_react.useRef)(connect);
793
+ const failConnectionRef = (0, import_react.useRef)(failConnection);
794
+ (0, import_react.useEffect)(() => {
795
+ connectRef.current = connect;
796
+ failConnectionRef.current = failConnection;
797
+ });
798
+ (0, import_react.useEffect)(() => {
799
+ const messageHandler = /* @__PURE__ */ __name((event) => {
800
+ if (event.origin !== window.location.origin) return;
801
+ if (event.data?.type === "mcp_auth_callback") {
802
+ addLog("info", "Received auth callback message.", event.data);
803
+ if (authTimeoutRef.current) clearTimeout(authTimeoutRef.current);
804
+ authTimeoutRef.current = null;
805
+ if (event.data.success) {
806
+ addLog("info", "Authentication successful via popup. Reconnecting client...");
807
+ if (!connectingRef.current) {
808
+ connectingRef.current = false;
809
+ connectRef.current();
810
+ } else {
811
+ addLog("warn", "Connection already in progress, skipping reconnection from auth callback");
812
+ }
813
+ } else {
814
+ failConnectionRef.current(`Authentication failed in callback: ${event.data.error || "Unknown reason."}`);
815
+ }
816
+ }
817
+ }, "messageHandler");
818
+ window.addEventListener("message", messageHandler);
819
+ addLog("debug", "Auth callback message listener added.");
820
+ return () => {
821
+ window.removeEventListener("message", messageHandler);
822
+ addLog("debug", "Auth callback message listener removed.");
823
+ if (authTimeoutRef.current) clearTimeout(authTimeoutRef.current);
824
+ };
825
+ }, [addLog]);
826
+ (0, import_react.useEffect)(() => {
827
+ isMountedRef.current = true;
828
+ if (!enabled || !url) {
829
+ addLog("debug", enabled ? "No server URL provided, skipping connection." : "Connection disabled via enabled flag.");
830
+ setState("discovering");
831
+ return () => {
832
+ isMountedRef.current = false;
833
+ };
834
+ }
835
+ addLog("debug", "useMcp mounted, initiating connection.");
836
+ connectAttemptRef.current = 0;
837
+ if (!authProviderRef.current || authProviderRef.current.serverUrl !== url) {
838
+ authProviderRef.current = new BrowserOAuthClientProvider(url, {
839
+ storageKeyPrefix,
840
+ clientName,
841
+ clientUri,
842
+ callbackUrl,
843
+ preventAutoAuth,
844
+ onPopupWindow
845
+ });
846
+ addLog("debug", "BrowserOAuthClientProvider initialized/updated on mount/option change.");
847
+ }
848
+ connect();
849
+ return () => {
850
+ isMountedRef.current = false;
851
+ addLog("debug", "useMcp unmounting, disconnecting.");
852
+ disconnect(true);
853
+ };
854
+ }, [url, enabled, storageKeyPrefix, callbackUrl, clientName, clientUri, clientConfig.name, clientConfig.version]);
855
+ (0, import_react.useEffect)(() => {
856
+ let retryTimeoutId = null;
857
+ if (state === "failed" && autoRetry && connectAttemptRef.current > 0) {
858
+ const delay = typeof autoRetry === "number" ? autoRetry : DEFAULT_RETRY_DELAY;
859
+ addLog("info", `Connection failed, auto-retrying in ${delay}ms...`);
860
+ retryTimeoutId = setTimeout(() => {
861
+ if (isMountedRef.current && stateRef.current === "failed") {
862
+ retry();
863
+ }
864
+ }, delay);
865
+ }
866
+ return () => {
867
+ if (retryTimeoutId) clearTimeout(retryTimeoutId);
868
+ };
869
+ }, [state, autoRetry, retry, addLog]);
870
+ return {
871
+ state,
872
+ tools,
873
+ resources,
874
+ resourceTemplates,
875
+ prompts,
876
+ error,
877
+ log,
878
+ authUrl,
879
+ callTool,
880
+ listResources,
881
+ readResource,
882
+ listPrompts,
883
+ getPrompt,
884
+ retry,
885
+ disconnect,
886
+ authenticate,
887
+ clearStorage
888
+ };
889
+ }
890
+ __name(useMcp, "useMcp");
891
+
892
+ // src/auth/callback.ts
893
+ var import_auth2 = require("@modelcontextprotocol/sdk/client/auth.js");
894
+ async function onMcpAuthorization() {
895
+ const queryParams = new URLSearchParams(window.location.search);
896
+ const code = queryParams.get("code");
897
+ const state = queryParams.get("state");
898
+ const error = queryParams.get("error");
899
+ const errorDescription = queryParams.get("error_description");
900
+ const logPrefix = "[mcp-callback]";
901
+ console.log(`${logPrefix} Handling callback...`, { code, state, error, errorDescription });
902
+ let provider = null;
903
+ let storedStateData = null;
904
+ const stateKey = state ? `mcp:auth:state_${state}` : null;
905
+ try {
906
+ if (error) {
907
+ throw new Error(`OAuth error: ${error} - ${errorDescription || "No description provided."}`);
908
+ }
909
+ if (!code) {
910
+ throw new Error("Authorization code not found in callback query parameters.");
911
+ }
912
+ if (!state || !stateKey) {
913
+ throw new Error("State parameter not found or invalid in callback query parameters.");
914
+ }
915
+ const storedStateJSON = localStorage.getItem(stateKey);
916
+ if (!storedStateJSON) {
917
+ throw new Error(`Invalid or expired state parameter "${state}". No matching state found in storage.`);
918
+ }
919
+ try {
920
+ storedStateData = JSON.parse(storedStateJSON);
921
+ } catch (e) {
922
+ throw new Error("Failed to parse stored OAuth state.");
923
+ }
924
+ if (!storedStateData.expiry || storedStateData.expiry < Date.now()) {
925
+ localStorage.removeItem(stateKey);
926
+ throw new Error("OAuth state has expired. Please try initiating authentication again.");
927
+ }
928
+ if (!storedStateData.providerOptions) {
929
+ throw new Error("Stored state is missing required provider options.");
930
+ }
931
+ const { serverUrl, ...providerOptions } = storedStateData.providerOptions;
932
+ console.log(`${logPrefix} Re-instantiating provider for server: ${serverUrl}`);
933
+ provider = new BrowserOAuthClientProvider(serverUrl, providerOptions);
934
+ console.log(`${logPrefix} Calling SDK auth() to exchange code...`);
935
+ const authResult = await (0, import_auth2.auth)(provider, { serverUrl, authorizationCode: code });
936
+ if (authResult === "AUTHORIZED") {
937
+ console.log(`${logPrefix} Authorization successful via SDK auth(). Notifying opener...`);
938
+ if (window.opener && !window.opener.closed) {
939
+ window.opener.postMessage({ type: "mcp_auth_callback", success: true }, window.location.origin);
940
+ window.close();
941
+ } else {
942
+ console.warn(`${logPrefix} No opener window detected. Redirecting to root.`);
943
+ const pathParts = window.location.pathname.split("/").filter(Boolean);
944
+ const basePath = pathParts.length > 0 && pathParts[pathParts.length - 1] === "callback" ? "/" + pathParts.slice(0, -2).join("/") : "/";
945
+ window.location.href = basePath || "/";
946
+ }
947
+ localStorage.removeItem(stateKey);
948
+ } else {
949
+ console.warn(`${logPrefix} SDK auth() returned unexpected status: ${authResult}`);
950
+ throw new Error(`Unexpected result from authentication library: ${authResult}`);
951
+ }
952
+ } catch (err) {
953
+ console.error(`${logPrefix} Error during OAuth callback handling:`, err);
954
+ const errorMessage = err instanceof Error ? err.message : String(err);
955
+ if (window.opener && !window.opener.closed) {
956
+ window.opener.postMessage({ type: "mcp_auth_callback", success: false, error: errorMessage }, window.location.origin);
957
+ }
958
+ try {
959
+ document.body.innerHTML = `
960
+ <div style="font-family: sans-serif; padding: 20px;">
961
+ <h1>Authentication Error</h1>
962
+ <p style="color: red; background-color: #ffebeb; border: 1px solid red; padding: 10px; border-radius: 4px;">
963
+ ${errorMessage}
964
+ </p>
965
+ <p>You can close this window or <a href="#" onclick="window.close(); return false;">click here to close</a>.</p>
966
+ <pre style="font-size: 0.8em; color: #555; margin-top: 20px; white-space: pre-wrap;">${err instanceof Error ? err.stack : ""}</pre>
967
+ </div>
968
+ `;
969
+ } catch (displayError) {
970
+ console.error(`${logPrefix} Could not display error in callback window:`, displayError);
971
+ }
972
+ if (stateKey) {
973
+ localStorage.removeItem(stateKey);
974
+ }
975
+ if (provider) {
976
+ localStorage.removeItem(provider.getKey("code_verifier"));
977
+ localStorage.removeItem(provider.getKey("last_auth_url"));
978
+ }
979
+ }
980
+ }
981
+ __name(onMcpAuthorization, "onMcpAuthorization");
982
+ // Annotate the CommonJS export names for ESM import in node:
983
+ 0 && (module.exports = {
984
+ onMcpAuthorization,
985
+ useMcp
986
+ });