@mcp-use/client 2.1.0 → 2.1.1-canary.1

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.
package/dist/index.js CHANGED
@@ -142,6 +142,268 @@ var init_logging = __esm({
142
142
  }
143
143
  });
144
144
 
145
+ // src/auth/popup.ts
146
+ function hasStoredTokens(tokensKey) {
147
+ try {
148
+ return typeof localStorage !== "undefined" && !!localStorage.getItem(tokensKey);
149
+ } catch {
150
+ return false;
151
+ }
152
+ }
153
+ function runAuthPopup({
154
+ popup,
155
+ state,
156
+ tokensKey,
157
+ timeoutMs = 5 * 6e4,
158
+ closePollMs = 1e3,
159
+ closeGraceMs = 2e4,
160
+ expectedOrigin = typeof window !== "undefined" ? window.location.origin : ""
161
+ }) {
162
+ return new Promise((resolve) => {
163
+ let settled = false;
164
+ let closeTimer = null;
165
+ let timeoutTimer = null;
166
+ let graceTimer = null;
167
+ let broadcastChannel = null;
168
+ const cleanup = () => {
169
+ if (closeTimer) {
170
+ clearInterval(closeTimer);
171
+ closeTimer = null;
172
+ }
173
+ if (timeoutTimer) {
174
+ clearTimeout(timeoutTimer);
175
+ timeoutTimer = null;
176
+ }
177
+ if (graceTimer) {
178
+ clearTimeout(graceTimer);
179
+ graceTimer = null;
180
+ }
181
+ if (typeof window !== "undefined") {
182
+ window.removeEventListener("message", messageHandler);
183
+ window.removeEventListener("storage", storageHandler);
184
+ }
185
+ if (broadcastChannel) {
186
+ try {
187
+ broadcastChannel.removeEventListener("message", broadcastHandler);
188
+ broadcastChannel.close();
189
+ } catch {
190
+ }
191
+ broadcastChannel = null;
192
+ }
193
+ };
194
+ const settle = (result) => {
195
+ if (settled) return;
196
+ settled = true;
197
+ cleanup();
198
+ resolve(result);
199
+ };
200
+ const handlePayload = (payload) => {
201
+ if (!payload || payload.type !== MCP_AUTH_CALLBACK_MESSAGE_TYPE) return;
202
+ if (payload.state && state && payload.state !== state) return;
203
+ if (payload.success) {
204
+ settle({ kind: "success" });
205
+ } else {
206
+ settle({
207
+ kind: "error",
208
+ error: payload.error ?? "Authentication failed in callback."
209
+ });
210
+ }
211
+ };
212
+ const messageHandler = (event) => {
213
+ if (expectedOrigin && event.origin !== expectedOrigin) return;
214
+ handlePayload(event.data);
215
+ };
216
+ const broadcastHandler = (event) => {
217
+ handlePayload(event.data);
218
+ };
219
+ const storageHandler = (event) => {
220
+ if (event.key !== tokensKey) return;
221
+ if (event.newValue) settle({ kind: "success" });
222
+ };
223
+ if (typeof window !== "undefined") {
224
+ window.addEventListener("message", messageHandler);
225
+ window.addEventListener("storage", storageHandler);
226
+ }
227
+ if (typeof BroadcastChannel !== "undefined") {
228
+ try {
229
+ broadcastChannel = new BroadcastChannel(MCP_AUTH_BROADCAST_CHANNEL);
230
+ broadcastChannel.addEventListener("message", broadcastHandler);
231
+ } catch {
232
+ broadcastChannel = null;
233
+ }
234
+ }
235
+ if (popup) {
236
+ closeTimer = setInterval(() => {
237
+ if (settled) return;
238
+ let closed = false;
239
+ try {
240
+ closed = popup.closed;
241
+ } catch {
242
+ closed = false;
243
+ }
244
+ if (!closed) return;
245
+ if (closeTimer) {
246
+ clearInterval(closeTimer);
247
+ closeTimer = null;
248
+ }
249
+ if (hasStoredTokens(tokensKey)) {
250
+ settle({ kind: "success" });
251
+ return;
252
+ }
253
+ graceTimer = setTimeout(() => {
254
+ settle(
255
+ hasStoredTokens(tokensKey) ? { kind: "success" } : { kind: "cancelled" }
256
+ );
257
+ }, closeGraceMs);
258
+ }, closePollMs);
259
+ }
260
+ timeoutTimer = setTimeout(() => {
261
+ settle(
262
+ hasStoredTokens(tokensKey) ? { kind: "success" } : { kind: "timeout" }
263
+ );
264
+ }, timeoutMs);
265
+ });
266
+ }
267
+ var MCP_AUTH_BROADCAST_CHANNEL, MCP_AUTH_CALLBACK_MESSAGE_TYPE;
268
+ var init_popup = __esm({
269
+ "src/auth/popup.ts"() {
270
+ "use strict";
271
+ MCP_AUTH_BROADCAST_CHANNEL = "mcp_auth_callback";
272
+ MCP_AUTH_CALLBACK_MESSAGE_TYPE = "mcp_auth_callback";
273
+ }
274
+ });
275
+
276
+ // src/auth/flow.ts
277
+ import {
278
+ auth,
279
+ InsufficientScopeError,
280
+ UnauthorizedError
281
+ } from "@modelcontextprotocol/client";
282
+ function isUnauthorized(err, depth = 0) {
283
+ if (!err || depth > 5) return false;
284
+ if (err instanceof UnauthorizedError) return true;
285
+ if (err instanceof Error) {
286
+ const code = err.code;
287
+ if (code === 401) return true;
288
+ if (err.name === "UnauthorizedError") return true;
289
+ const message = err.message ?? "";
290
+ if (message.includes("401") || message.includes("Unauthorized")) {
291
+ return true;
292
+ }
293
+ if (err.cause && isUnauthorized(err.cause, depth + 1)) return true;
294
+ const data = err.data;
295
+ if (data?.cause && isUnauthorized(data.cause, depth + 1)) return true;
296
+ }
297
+ return false;
298
+ }
299
+ function isOAuthInteractionRequired(err, depth = 0) {
300
+ if (!err || depth > 5) return false;
301
+ if (err instanceof InsufficientScopeError || err instanceof UnauthorizedError) {
302
+ return true;
303
+ }
304
+ if (err instanceof Error) {
305
+ if (err.name === "InsufficientScopeError" || err.name === "UnauthorizedError") {
306
+ return true;
307
+ }
308
+ if (err.cause && isOAuthInteractionRequired(err.cause, depth + 1)) {
309
+ return true;
310
+ }
311
+ const data = err.data;
312
+ if (data?.cause && isOAuthInteractionRequired(data.cause, depth + 1)) {
313
+ return true;
314
+ }
315
+ }
316
+ return false;
317
+ }
318
+ async function completeOAuthFlow(provider, serverUrl, options = {}) {
319
+ const flowProvider = provider;
320
+ const timeoutMs = options.timeoutMs ?? DEFAULT_AUTH_TIMEOUT_MS;
321
+ const fetchFn = options.fetchFn ?? flowProvider.getProxyFetch?.() ?? void 0;
322
+ if (!flowProvider.hasPendingFlow) {
323
+ const result = await auth(provider, { serverUrl, fetchFn });
324
+ if (result === "AUTHORIZED") return;
325
+ if (result !== "REDIRECT") {
326
+ throw new Error(`Unexpected OAuth auth() result: ${result}`);
327
+ }
328
+ }
329
+ if (flowProvider.preventAutoAuth === true && typeof flowProvider.startAuthorization === "function") {
330
+ flowProvider.startAuthorization();
331
+ }
332
+ if (typeof flowProvider.getAuthorizationResponse === "function" || typeof flowProvider.getAuthorizationCode === "function") {
333
+ const response = typeof flowProvider.getAuthorizationResponse === "function" ? await flowProvider.getAuthorizationResponse() : { code: await flowProvider.getAuthorizationCode() };
334
+ if (options.finishAuthorization) {
335
+ await options.finishAuthorization(response.code, response.iss);
336
+ } else {
337
+ await auth(provider, {
338
+ serverUrl,
339
+ authorizationCode: response.code,
340
+ ...response.iss !== void 0 ? { iss: response.iss } : {},
341
+ fetchFn
342
+ });
343
+ }
344
+ return;
345
+ }
346
+ await waitForBrowserAuthComplete(flowProvider, timeoutMs);
347
+ }
348
+ async function waitForBrowserAuthComplete(provider, timeoutMs) {
349
+ if (typeof window === "undefined") {
350
+ throw new Error(
351
+ "OAuth redirect requires a browser environment or a provider with getAuthorizationCode()"
352
+ );
353
+ }
354
+ if (provider.useRedirectFlow) {
355
+ await new Promise(() => {
356
+ });
357
+ return;
358
+ }
359
+ const tokensKey = provider.getKey?.("tokens");
360
+ if (!tokensKey) {
361
+ throw new Error(
362
+ "Browser OAuth provider must expose getKey() for token storage"
363
+ );
364
+ }
365
+ let state = null;
366
+ const authUrl = provider.getLastAttemptedAuthUrl?.();
367
+ if (authUrl) {
368
+ try {
369
+ state = new URL(authUrl).searchParams.get("state");
370
+ } catch {
371
+ }
372
+ }
373
+ try {
374
+ const result = await runAuthPopup({
375
+ popup: null,
376
+ state,
377
+ tokensKey,
378
+ timeoutMs
379
+ });
380
+ switch (result.kind) {
381
+ case "success":
382
+ return;
383
+ case "cancelled":
384
+ throw new Error("OAuth authentication was cancelled.");
385
+ case "timeout":
386
+ throw new Error(
387
+ `OAuth callback not received within ${timeoutMs}ms. Ensure /oauth/callback calls onMcpAuthorization().`
388
+ );
389
+ case "error":
390
+ throw new Error(result.error);
391
+ default:
392
+ throw new Error("Unexpected OAuth popup result");
393
+ }
394
+ } finally {
395
+ provider.markFlowComplete?.();
396
+ }
397
+ }
398
+ var DEFAULT_AUTH_TIMEOUT_MS;
399
+ var init_flow = __esm({
400
+ "src/auth/flow.ts"() {
401
+ "use strict";
402
+ init_popup();
403
+ DEFAULT_AUTH_TIMEOUT_MS = 5 * 6e4;
404
+ }
405
+ });
406
+
145
407
  // src/utils/json-schema-validator.ts
146
408
  import {
147
409
  CfWorkerJsonSchemaValidator
@@ -190,6 +452,7 @@ var init_base = __esm({
190
452
  "src/transport/base.ts"() {
191
453
  "use strict";
192
454
  init_logging();
455
+ init_flow();
193
456
  init_connector_telemetry();
194
457
  passthroughResultSchema = {
195
458
  "~standard": {
@@ -204,6 +467,7 @@ var init_base = __esm({
204
467
  toolsCache = null;
205
468
  capabilitiesCache = null;
206
469
  serverInfoCache = null;
470
+ authorizationCache;
207
471
  connected = false;
208
472
  opts;
209
473
  notificationHandlers = [];
@@ -467,6 +731,28 @@ var init_base = __esm({
467
731
  "setupElicitationHandler: Elicitation handler registered successfully"
468
732
  );
469
733
  }
734
+ /**
735
+ * Run one logical MCP operation. HTTP connectors override this host seam to
736
+ * finish an SDK-started interactive OAuth flow and retry exactly once.
737
+ */
738
+ async executeRequest(operation) {
739
+ return operation();
740
+ }
741
+ /** OAuth state discovered for the active connection, when available. */
742
+ get authorization() {
743
+ return this.authorizationCache;
744
+ }
745
+ /**
746
+ * Discover optional authorization metadata without delaying connection
747
+ * readiness. HTTP connectors override this with RFC 9728 discovery.
748
+ */
749
+ async discoverAuthorization() {
750
+ return this.authorization;
751
+ }
752
+ /** Start optional OAuth for a connected mixed-auth server. */
753
+ async authenticate() {
754
+ throw new Error("This connector does not support interactive OAuth");
755
+ }
470
756
  /**
471
757
  * Disconnects the SDK client and releases transport resources.
472
758
  *
@@ -514,13 +800,13 @@ var init_base = __esm({
514
800
  icons: serverInfo.icons
515
801
  } : null;
516
802
  try {
517
- const listToolsRes = await this.client.listTools(
518
- void 0,
519
- defaultRequestOptions
803
+ const listToolsRes = await this.executeRequest(
804
+ () => this.client.listTools(void 0, defaultRequestOptions)
520
805
  );
521
806
  this.toolsCache = listToolsRes.tools ?? [];
522
807
  logger.debug(`Fetched ${this.toolsCache.length} tools from server`);
523
808
  } catch (err) {
809
+ if (isOAuthInteractionRequired(err)) throw err;
524
810
  const error = err;
525
811
  if (error.code === -32601) {
526
812
  logger.debug("Server does not implement tools/list, assuming no tools");
@@ -594,9 +880,8 @@ var init_base = __esm({
594
880
  const progressHandler = enhancedOptions?.onprogress;
595
881
  if (progressHandler) this.activeProgressHandlers.add(progressHandler);
596
882
  try {
597
- const res = await this.client.callTool(
598
- { name, arguments: args },
599
- enhancedOptions
883
+ const res = await this.executeRequest(
884
+ () => this.client.callTool({ name, arguments: args }, enhancedOptions)
600
885
  );
601
886
  logger.debug(`Tool '${name}' returned`, res);
602
887
  return res;
@@ -616,7 +901,9 @@ var init_base = __esm({
616
901
  throw new Error("MCP client is not connected");
617
902
  }
618
903
  logger.debug("[listTools] Fetching fresh tools from server...");
619
- const result = await this.client.listTools(void 0, options);
904
+ const result = await this.executeRequest(
905
+ () => this.client.listTools(void 0, options)
906
+ );
620
907
  const tools = result.tools ? [...result.tools] : [];
621
908
  logger.debug(
622
909
  `[listTools] Returned ${tools.length} tools:`,
@@ -636,7 +923,9 @@ var init_base = __esm({
636
923
  throw new Error("MCP client is not connected");
637
924
  }
638
925
  logger.debug("Listing resources", cursor ? `with cursor: ${cursor}` : "");
639
- return await this.client.listResources({ cursor }, options);
926
+ return await this.executeRequest(
927
+ () => this.client.listResources({ cursor }, options)
928
+ );
640
929
  }
641
930
  /**
642
931
  * List all resources from the server, automatically handling pagination
@@ -654,14 +943,16 @@ var init_base = __esm({
654
943
  }
655
944
  try {
656
945
  logger.debug("Listing all resources (with auto-pagination)");
657
- const allResources = [];
658
- let cursor = void 0;
659
- do {
660
- const result = await this.client.listResources({ cursor }, options);
661
- allResources.push(...result.resources || []);
662
- cursor = result.nextCursor;
663
- } while (cursor);
664
- return { resources: allResources };
946
+ return await this.executeRequest(async () => {
947
+ const allResources = [];
948
+ let cursor = void 0;
949
+ do {
950
+ const result = await this.client.listResources({ cursor }, options);
951
+ allResources.push(...result.resources || []);
952
+ cursor = result.nextCursor;
953
+ } while (cursor);
954
+ return { resources: allResources };
955
+ });
665
956
  } catch (err) {
666
957
  const error = err;
667
958
  if (error.code === -32601) {
@@ -682,7 +973,9 @@ var init_base = __esm({
682
973
  throw new Error("MCP client is not connected");
683
974
  }
684
975
  logger.debug("Listing resource templates");
685
- return await this.client.listResourceTemplates(void 0, options);
976
+ return await this.executeRequest(
977
+ () => this.client.listResourceTemplates(void 0, options)
978
+ );
686
979
  }
687
980
  /**
688
981
  * Request completion suggestions for a prompt or resource template argument
@@ -696,7 +989,9 @@ var init_base = __esm({
696
989
  throw new Error("MCP client is not connected");
697
990
  }
698
991
  logger.debug("[complete] Requesting completions for:", params.ref);
699
- const result = await this.client.complete(params, options);
992
+ const result = await this.executeRequest(
993
+ () => this.client.complete(params, options)
994
+ );
700
995
  logger.debug(
701
996
  `[complete] Received ${result.completion.values.length} suggestions`
702
997
  );
@@ -714,7 +1009,9 @@ var init_base = __esm({
714
1009
  throw new Error("MCP client is not connected");
715
1010
  }
716
1011
  logger.debug(`Reading resource ${uri}`);
717
- const res = await this.client.readResource({ uri }, options);
1012
+ const res = await this.executeRequest(
1013
+ () => this.client.readResource({ uri }, options)
1014
+ );
718
1015
  return res;
719
1016
  }
720
1017
  /**
@@ -728,7 +1025,9 @@ var init_base = __esm({
728
1025
  throw new Error("MCP client is not connected");
729
1026
  }
730
1027
  logger.debug(`Subscribing to resource: ${uri}`);
731
- return await this.client.subscribeResource({ uri }, options);
1028
+ return await this.executeRequest(
1029
+ () => this.client.subscribeResource({ uri }, options)
1030
+ );
732
1031
  }
733
1032
  /**
734
1033
  * Unsubscribe from resource updates
@@ -741,7 +1040,9 @@ var init_base = __esm({
741
1040
  throw new Error("MCP client is not connected");
742
1041
  }
743
1042
  logger.debug(`Unsubscribing from resource: ${uri}`);
744
- return await this.client.unsubscribeResource({ uri }, options);
1043
+ return await this.executeRequest(
1044
+ () => this.client.unsubscribeResource({ uri }, options)
1045
+ );
745
1046
  }
746
1047
  /**
747
1048
  * Lists prompts exposed by the server.
@@ -758,7 +1059,7 @@ var init_base = __esm({
758
1059
  }
759
1060
  try {
760
1061
  logger.debug("Listing prompts");
761
- return await this.client.listPrompts();
1062
+ return await this.executeRequest(() => this.client.listPrompts());
762
1063
  } catch (err) {
763
1064
  const error = err;
764
1065
  if (error.code === -32601) {
@@ -780,7 +1081,9 @@ var init_base = __esm({
780
1081
  throw new Error("MCP client is not connected");
781
1082
  }
782
1083
  logger.debug(`Getting prompt ${name}`);
783
- return await this.client.getPrompt({ name, arguments: args });
1084
+ return await this.executeRequest(
1085
+ () => this.client.getPrompt({ name, arguments: args })
1086
+ );
784
1087
  }
785
1088
  /**
786
1089
  * Sends a raw, potentially non-standard request through the SDK client.
@@ -795,10 +1098,12 @@ var init_base = __esm({
795
1098
  throw new Error("MCP client is not connected");
796
1099
  }
797
1100
  logger.debug(`Sending raw request '${method}' with params`, params);
798
- return await this.client.request(
799
- { method, params: params ?? {} },
800
- passthroughResultSchema,
801
- options
1101
+ return await this.executeRequest(
1102
+ () => this.client.request(
1103
+ { method, params: params ?? {} },
1104
+ passthroughResultSchema,
1105
+ options
1106
+ )
802
1107
  );
803
1108
  }
804
1109
  /**
@@ -831,6 +1136,7 @@ var init_base = __esm({
831
1136
  }
832
1137
  }
833
1138
  this.toolsCache = null;
1139
+ this.authorizationCache = void 0;
834
1140
  if (issues.length) {
835
1141
  logger.warn(`Resource cleanup finished with ${issues.length} issue(s)`);
836
1142
  }
@@ -1219,7 +1525,7 @@ init_connector_telemetry();
1219
1525
  init_logging();
1220
1526
 
1221
1527
  // src/utils/version.ts
1222
- var VERSION = "2.1.0";
1528
+ var VERSION = "2.1.1-canary.1";
1223
1529
  function getPackageVersion() {
1224
1530
  return VERSION;
1225
1531
  }
@@ -1618,396 +1924,173 @@ var Telemetry = class _Telemetry {
1618
1924
  const p = capturePostHog({
1619
1925
  host: HOST,
1620
1926
  apiKey: PROJECT_API_KEY,
1621
- event: event.name,
1622
- distinctId: currentUserId,
1623
- properties
1624
- });
1625
- this._pending.add(p);
1626
- void p.finally(() => this._pending.delete(p));
1627
- }
1628
- async trackAgentExecution(data) {
1629
- if (!this.isEnabled) return;
1630
- await this.capture(new MCPAgentExecutionEvent(data));
1631
- }
1632
- async trackMCPClientInit(data) {
1633
- if (!this.isEnabled) return;
1634
- await this.capture(new MCPClientInitEvent(data));
1635
- }
1636
- async trackConnectorInit(data) {
1637
- if (!this.isEnabled) return;
1638
- await this.capture(new ConnectorInitEvent(data));
1639
- }
1640
- async trackClientAddServer(serverName, serverConfig) {
1641
- if (!this.isEnabled) return;
1642
- await this.capture(new ClientAddServerEvent({ serverName, serverConfig }));
1643
- }
1644
- async trackClientRemoveServer(serverName) {
1645
- if (!this.isEnabled) return;
1646
- await this.capture(new ClientRemoveServerEvent({ serverName }));
1647
- }
1648
- async trackUseMcpConnection(data) {
1649
- if (!this.isEnabled) return;
1650
- await this.capture({
1651
- name: "usemcp_connection",
1652
- properties: {
1653
- url_domain: new URL(data.url).hostname,
1654
- transport_type: data.transportType,
1655
- success: data.success,
1656
- error_type: data.errorType ?? null,
1657
- connection_time_ms: data.connectionTimeMs ?? null,
1658
- has_oauth: data.hasOAuth,
1659
- has_sampling: data.hasSampling,
1660
- has_elicitation: data.hasElicitation
1661
- }
1662
- });
1663
- }
1664
- async trackUseMcpToolCall(data) {
1665
- if (!this.isEnabled) return;
1666
- await this.capture({
1667
- name: "usemcp_tool_call",
1668
- properties: {
1669
- tool_name: data.toolName,
1670
- success: data.success,
1671
- error_type: data.errorType ?? null,
1672
- execution_time_ms: data.executionTimeMs ?? null
1673
- }
1674
- });
1675
- }
1676
- async trackUseMcpResourceRead(data) {
1677
- if (!this.isEnabled) return;
1678
- await this.capture({
1679
- name: "usemcp_resource_read",
1680
- properties: {
1681
- resource_uri_scheme: data.resourceUri.split(":")[0],
1682
- success: data.success,
1683
- error_type: data.errorType ?? null
1684
- }
1685
- });
1686
- }
1687
- identify(userId, properties) {
1688
- this._currUserId = userId;
1689
- this._storage?.setUserId(userId);
1690
- if (this._telemetryEnabled) {
1691
- void capturePostHog({
1692
- host: HOST,
1693
- apiKey: PROJECT_API_KEY,
1694
- event: "$identify",
1695
- distinctId: userId,
1696
- properties: { $set: properties ?? {} }
1697
- });
1698
- }
1699
- }
1700
- reset() {
1701
- this._currUserId = null;
1702
- }
1703
- flush() {
1704
- void Promise.allSettled([...this._pending]);
1705
- }
1706
- async shutdown() {
1707
- try {
1708
- await Promise.allSettled([...this._pending]);
1709
- logger.debug("Telemetry fetch captures flushed");
1710
- } catch (e) {
1711
- logger.debug(`Error flushing telemetry captures: ${e}`);
1712
- }
1713
- }
1714
- };
1715
- var Tel = Telemetry;
1716
- function setTelemetrySource(source) {
1717
- Tel.getInstance().setSource(source);
1718
- }
1719
- function setProductVersion(version) {
1720
- Tel.getInstance().setProductVersion(version);
1721
- }
1722
-
1723
- // src/telemetry/telemetry-node.ts
1724
- function getCacheHome(os, path2) {
1725
- const envVar = process.env.XDG_CACHE_HOME;
1726
- if (envVar && path2.isAbsolute(envVar)) {
1727
- return envVar;
1728
- }
1729
- const homeDir = os.homedir();
1730
- if (process.platform === "win32") {
1731
- const appdata = process.env.LOCALAPPDATA || process.env.APPDATA;
1732
- if (appdata) return appdata;
1733
- return path2.join(homeDir, "AppData", "Local");
1734
- }
1735
- if (process.platform === "darwin") {
1736
- return path2.join(homeDir, "Library", "Caches");
1737
- }
1738
- return path2.join(homeDir, ".cache");
1739
- }
1740
- function createFsStorage() {
1741
- let fs2;
1742
- let os;
1743
- let path2;
1744
- try {
1745
- fs2 = __require("fs");
1746
- os = __require("os");
1747
- path2 = __require("path");
1748
- } catch {
1749
- return {
1750
- getUserId: () => null,
1751
- setUserId: () => void 0
1752
- };
1753
- }
1754
- const cacheHome = getCacheHome(os, path2);
1755
- const userIdPath = path2.join(cacheHome, "mcp_use_3", "telemetry_user_id");
1756
- return {
1757
- getUserId() {
1758
- try {
1759
- if (!fs2.existsSync(userIdPath)) return null;
1760
- return fs2.readFileSync(userIdPath, "utf-8").trim() || null;
1761
- } catch {
1762
- return null;
1763
- }
1764
- },
1765
- setUserId(id) {
1766
- try {
1767
- fs2.mkdirSync(path2.dirname(userIdPath), { recursive: true });
1768
- fs2.writeFileSync(userIdPath, id);
1769
- } catch {
1770
- }
1771
- }
1772
- };
1773
- }
1774
- configureTelemetryStorage(createFsStorage());
1775
-
1776
- // src/telemetry/configure-node.ts
1777
- setClientTelemetryTracker({
1778
- addServer: (name, config) => Telemetry.getInstance().trackClientAddServer(name, config).catch(() => void 0),
1779
- removeServer: (name) => Telemetry.getInstance().trackClientRemoveServer(name).catch(() => void 0)
1780
- });
1781
- setConnectorTelemetryTracker(
1782
- (data) => Telemetry.getInstance().trackConnectorInit(data).catch(() => void 0)
1783
- );
1784
-
1785
- // src/index.ts
1786
- import { auth as auth2, UnauthorizedError as UnauthorizedError3 } from "@modelcontextprotocol/client";
1787
-
1788
- // src/auth/flow.ts
1789
- import {
1790
- auth,
1791
- UnauthorizedError
1792
- } from "@modelcontextprotocol/client";
1793
-
1794
- // src/auth/popup.ts
1795
- var MCP_AUTH_BROADCAST_CHANNEL = "mcp_auth_callback";
1796
- var MCP_AUTH_CALLBACK_MESSAGE_TYPE = "mcp_auth_callback";
1797
- function hasStoredTokens(tokensKey) {
1798
- try {
1799
- return typeof localStorage !== "undefined" && !!localStorage.getItem(tokensKey);
1800
- } catch {
1801
- return false;
1802
- }
1803
- }
1804
- function runAuthPopup({
1805
- popup,
1806
- state,
1807
- tokensKey,
1808
- timeoutMs = 5 * 6e4,
1809
- closePollMs = 1e3,
1810
- closeGraceMs = 2e4,
1811
- expectedOrigin = typeof window !== "undefined" ? window.location.origin : ""
1812
- }) {
1813
- return new Promise((resolve) => {
1814
- let settled = false;
1815
- let closeTimer = null;
1816
- let timeoutTimer = null;
1817
- let graceTimer = null;
1818
- let broadcastChannel = null;
1819
- const cleanup = () => {
1820
- if (closeTimer) {
1821
- clearInterval(closeTimer);
1822
- closeTimer = null;
1823
- }
1824
- if (timeoutTimer) {
1825
- clearTimeout(timeoutTimer);
1826
- timeoutTimer = null;
1827
- }
1828
- if (graceTimer) {
1829
- clearTimeout(graceTimer);
1830
- graceTimer = null;
1831
- }
1832
- if (typeof window !== "undefined") {
1833
- window.removeEventListener("message", messageHandler);
1834
- window.removeEventListener("storage", storageHandler);
1835
- }
1836
- if (broadcastChannel) {
1837
- try {
1838
- broadcastChannel.removeEventListener("message", broadcastHandler);
1839
- broadcastChannel.close();
1840
- } catch {
1841
- }
1842
- broadcastChannel = null;
1843
- }
1844
- };
1845
- const settle = (result) => {
1846
- if (settled) return;
1847
- settled = true;
1848
- cleanup();
1849
- resolve(result);
1850
- };
1851
- const handlePayload = (payload) => {
1852
- if (!payload || payload.type !== MCP_AUTH_CALLBACK_MESSAGE_TYPE) return;
1853
- if (payload.state && state && payload.state !== state) return;
1854
- if (payload.success) {
1855
- settle({ kind: "success" });
1856
- } else {
1857
- settle({
1858
- kind: "error",
1859
- error: payload.error ?? "Authentication failed in callback."
1860
- });
1861
- }
1862
- };
1863
- const messageHandler = (event) => {
1864
- if (expectedOrigin && event.origin !== expectedOrigin) return;
1865
- handlePayload(event.data);
1866
- };
1867
- const broadcastHandler = (event) => {
1868
- handlePayload(event.data);
1869
- };
1870
- const storageHandler = (event) => {
1871
- if (event.key !== tokensKey) return;
1872
- if (event.newValue) settle({ kind: "success" });
1873
- };
1874
- if (typeof window !== "undefined") {
1875
- window.addEventListener("message", messageHandler);
1876
- window.addEventListener("storage", storageHandler);
1877
- }
1878
- if (typeof BroadcastChannel !== "undefined") {
1879
- try {
1880
- broadcastChannel = new BroadcastChannel(MCP_AUTH_BROADCAST_CHANNEL);
1881
- broadcastChannel.addEventListener("message", broadcastHandler);
1882
- } catch {
1883
- broadcastChannel = null;
1884
- }
1885
- }
1886
- if (popup) {
1887
- closeTimer = setInterval(() => {
1888
- if (settled) return;
1889
- let closed = false;
1890
- try {
1891
- closed = popup.closed;
1892
- } catch {
1893
- closed = false;
1894
- }
1895
- if (!closed) return;
1896
- if (closeTimer) {
1897
- clearInterval(closeTimer);
1898
- closeTimer = null;
1899
- }
1900
- if (hasStoredTokens(tokensKey)) {
1901
- settle({ kind: "success" });
1902
- return;
1903
- }
1904
- graceTimer = setTimeout(() => {
1905
- settle(
1906
- hasStoredTokens(tokensKey) ? { kind: "success" } : { kind: "cancelled" }
1907
- );
1908
- }, closeGraceMs);
1909
- }, closePollMs);
1910
- }
1911
- timeoutTimer = setTimeout(() => {
1912
- settle(
1913
- hasStoredTokens(tokensKey) ? { kind: "success" } : { kind: "timeout" }
1914
- );
1915
- }, timeoutMs);
1916
- });
1917
- }
1918
-
1919
- // src/auth/flow.ts
1920
- var DEFAULT_AUTH_TIMEOUT_MS = 5 * 6e4;
1921
- function isUnauthorized(err, depth = 0) {
1922
- if (!err || depth > 5) return false;
1923
- if (err instanceof UnauthorizedError) return true;
1924
- if (err instanceof Error) {
1925
- const code = err.code;
1926
- if (code === 401) return true;
1927
- if (err.name === "UnauthorizedError") return true;
1928
- const message = err.message ?? "";
1929
- if (message.includes("401") || message.includes("Unauthorized")) {
1930
- return true;
1931
- }
1932
- if (err.cause && isUnauthorized(err.cause, depth + 1)) return true;
1933
- const data = err.data;
1934
- if (data?.cause && isUnauthorized(data.cause, depth + 1)) return true;
1927
+ event: event.name,
1928
+ distinctId: currentUserId,
1929
+ properties
1930
+ });
1931
+ this._pending.add(p);
1932
+ void p.finally(() => this._pending.delete(p));
1935
1933
  }
1936
- return false;
1937
- }
1938
- async function completeOAuthFlow(provider, serverUrl, options = {}) {
1939
- const flowProvider = provider;
1940
- const timeoutMs = options.timeoutMs ?? DEFAULT_AUTH_TIMEOUT_MS;
1941
- const fetchFn = options.fetchFn ?? flowProvider.getProxyFetch?.() ?? void 0;
1942
- if (!flowProvider.hasPendingFlow) {
1943
- const result = await auth(provider, { serverUrl, fetchFn });
1944
- if (result === "AUTHORIZED") return;
1945
- if (result !== "REDIRECT") {
1946
- throw new Error(`Unexpected OAuth auth() result: ${result}`);
1947
- }
1934
+ async trackAgentExecution(data) {
1935
+ if (!this.isEnabled) return;
1936
+ await this.capture(new MCPAgentExecutionEvent(data));
1948
1937
  }
1949
- if (typeof flowProvider.getAuthorizationResponse === "function" || typeof flowProvider.getAuthorizationCode === "function") {
1950
- const response = typeof flowProvider.getAuthorizationResponse === "function" ? await flowProvider.getAuthorizationResponse() : { code: await flowProvider.getAuthorizationCode() };
1951
- await auth(provider, {
1952
- serverUrl,
1953
- authorizationCode: response.code,
1954
- ...response.iss !== void 0 ? { iss: response.iss } : {},
1955
- fetchFn
1938
+ async trackMCPClientInit(data) {
1939
+ if (!this.isEnabled) return;
1940
+ await this.capture(new MCPClientInitEvent(data));
1941
+ }
1942
+ async trackConnectorInit(data) {
1943
+ if (!this.isEnabled) return;
1944
+ await this.capture(new ConnectorInitEvent(data));
1945
+ }
1946
+ async trackClientAddServer(serverName, serverConfig) {
1947
+ if (!this.isEnabled) return;
1948
+ await this.capture(new ClientAddServerEvent({ serverName, serverConfig }));
1949
+ }
1950
+ async trackClientRemoveServer(serverName) {
1951
+ if (!this.isEnabled) return;
1952
+ await this.capture(new ClientRemoveServerEvent({ serverName }));
1953
+ }
1954
+ async trackUseMcpConnection(data) {
1955
+ if (!this.isEnabled) return;
1956
+ await this.capture({
1957
+ name: "usemcp_connection",
1958
+ properties: {
1959
+ url_domain: new URL(data.url).hostname,
1960
+ transport_type: data.transportType,
1961
+ success: data.success,
1962
+ error_type: data.errorType ?? null,
1963
+ connection_time_ms: data.connectionTimeMs ?? null,
1964
+ has_oauth: data.hasOAuth,
1965
+ has_sampling: data.hasSampling,
1966
+ has_elicitation: data.hasElicitation
1967
+ }
1956
1968
  });
1957
- return;
1958
1969
  }
1959
- await waitForBrowserAuthComplete(flowProvider, timeoutMs);
1960
- }
1961
- async function waitForBrowserAuthComplete(provider, timeoutMs) {
1962
- if (typeof window === "undefined") {
1963
- throw new Error(
1964
- "OAuth redirect requires a browser environment or a provider with getAuthorizationCode()"
1965
- );
1970
+ async trackUseMcpToolCall(data) {
1971
+ if (!this.isEnabled) return;
1972
+ await this.capture({
1973
+ name: "usemcp_tool_call",
1974
+ properties: {
1975
+ tool_name: data.toolName,
1976
+ success: data.success,
1977
+ error_type: data.errorType ?? null,
1978
+ execution_time_ms: data.executionTimeMs ?? null
1979
+ }
1980
+ });
1966
1981
  }
1967
- if (provider.useRedirectFlow) {
1968
- await new Promise(() => {
1982
+ async trackUseMcpResourceRead(data) {
1983
+ if (!this.isEnabled) return;
1984
+ await this.capture({
1985
+ name: "usemcp_resource_read",
1986
+ properties: {
1987
+ resource_uri_scheme: data.resourceUri.split(":")[0],
1988
+ success: data.success,
1989
+ error_type: data.errorType ?? null
1990
+ }
1969
1991
  });
1970
- return;
1971
1992
  }
1972
- const tokensKey = provider.getKey?.("tokens");
1973
- if (!tokensKey) {
1974
- throw new Error(
1975
- "Browser OAuth provider must expose getKey() for token storage"
1976
- );
1993
+ identify(userId, properties) {
1994
+ this._currUserId = userId;
1995
+ this._storage?.setUserId(userId);
1996
+ if (this._telemetryEnabled) {
1997
+ void capturePostHog({
1998
+ host: HOST,
1999
+ apiKey: PROJECT_API_KEY,
2000
+ event: "$identify",
2001
+ distinctId: userId,
2002
+ properties: { $set: properties ?? {} }
2003
+ });
2004
+ }
1977
2005
  }
1978
- let state = null;
1979
- const authUrl = provider.getLastAttemptedAuthUrl?.();
1980
- if (authUrl) {
2006
+ reset() {
2007
+ this._currUserId = null;
2008
+ }
2009
+ flush() {
2010
+ void Promise.allSettled([...this._pending]);
2011
+ }
2012
+ async shutdown() {
1981
2013
  try {
1982
- state = new URL(authUrl).searchParams.get("state");
1983
- } catch {
2014
+ await Promise.allSettled([...this._pending]);
2015
+ logger.debug("Telemetry fetch captures flushed");
2016
+ } catch (e) {
2017
+ logger.debug(`Error flushing telemetry captures: ${e}`);
1984
2018
  }
1985
2019
  }
2020
+ };
2021
+ var Tel = Telemetry;
2022
+ function setTelemetrySource(source) {
2023
+ Tel.getInstance().setSource(source);
2024
+ }
2025
+ function setProductVersion(version) {
2026
+ Tel.getInstance().setProductVersion(version);
2027
+ }
2028
+
2029
+ // src/telemetry/telemetry-node.ts
2030
+ function getCacheHome(os, path2) {
2031
+ const envVar = process.env.XDG_CACHE_HOME;
2032
+ if (envVar && path2.isAbsolute(envVar)) {
2033
+ return envVar;
2034
+ }
2035
+ const homeDir = os.homedir();
2036
+ if (process.platform === "win32") {
2037
+ const appdata = process.env.LOCALAPPDATA || process.env.APPDATA;
2038
+ if (appdata) return appdata;
2039
+ return path2.join(homeDir, "AppData", "Local");
2040
+ }
2041
+ if (process.platform === "darwin") {
2042
+ return path2.join(homeDir, "Library", "Caches");
2043
+ }
2044
+ return path2.join(homeDir, ".cache");
2045
+ }
2046
+ function createFsStorage() {
2047
+ let fs2;
2048
+ let os;
2049
+ let path2;
1986
2050
  try {
1987
- const result = await runAuthPopup({
1988
- popup: null,
1989
- state,
1990
- tokensKey,
1991
- timeoutMs
1992
- });
1993
- switch (result.kind) {
1994
- case "success":
1995
- return;
1996
- case "cancelled":
1997
- throw new Error("OAuth authentication was cancelled.");
1998
- case "timeout":
1999
- throw new Error(
2000
- `OAuth callback not received within ${timeoutMs}ms. Ensure /oauth/callback calls onMcpAuthorization().`
2001
- );
2002
- case "error":
2003
- throw new Error(result.error);
2004
- default:
2005
- throw new Error("Unexpected OAuth popup result");
2006
- }
2007
- } finally {
2008
- provider.markFlowComplete?.();
2051
+ fs2 = __require("fs");
2052
+ os = __require("os");
2053
+ path2 = __require("path");
2054
+ } catch {
2055
+ return {
2056
+ getUserId: () => null,
2057
+ setUserId: () => void 0
2058
+ };
2009
2059
  }
2060
+ const cacheHome = getCacheHome(os, path2);
2061
+ const userIdPath = path2.join(cacheHome, "mcp_use_3", "telemetry_user_id");
2062
+ return {
2063
+ getUserId() {
2064
+ try {
2065
+ if (!fs2.existsSync(userIdPath)) return null;
2066
+ return fs2.readFileSync(userIdPath, "utf-8").trim() || null;
2067
+ } catch {
2068
+ return null;
2069
+ }
2070
+ },
2071
+ setUserId(id) {
2072
+ try {
2073
+ fs2.mkdirSync(path2.dirname(userIdPath), { recursive: true });
2074
+ fs2.writeFileSync(userIdPath, id);
2075
+ } catch {
2076
+ }
2077
+ }
2078
+ };
2010
2079
  }
2080
+ configureTelemetryStorage(createFsStorage());
2081
+
2082
+ // src/telemetry/configure-node.ts
2083
+ setClientTelemetryTracker({
2084
+ addServer: (name, config) => Telemetry.getInstance().trackClientAddServer(name, config).catch(() => void 0),
2085
+ removeServer: (name) => Telemetry.getInstance().trackClientRemoveServer(name).catch(() => void 0)
2086
+ });
2087
+ setConnectorTelemetryTracker(
2088
+ (data) => Telemetry.getInstance().trackConnectorInit(data).catch(() => void 0)
2089
+ );
2090
+
2091
+ // src/index.ts
2092
+ init_flow();
2093
+ import { auth as auth2, UnauthorizedError as UnauthorizedError3 } from "@modelcontextprotocol/client";
2011
2094
 
2012
2095
  // src/auth/node.ts
2013
2096
  import { createServer as createNetServer } from "net";
@@ -2840,16 +2923,19 @@ async function createOAuthProvider(serverUrl, options = {}) {
2840
2923
  }
2841
2924
 
2842
2925
  // src/transport/http.ts
2926
+ init_flow();
2843
2927
  init_json_schema_validator();
2844
2928
  init_logging();
2845
2929
  init_base();
2846
2930
  import {
2847
2931
  Client,
2932
+ discoverOAuthProtectedResourceMetadata,
2848
2933
  SdkError,
2849
2934
  SdkHttpError,
2850
2935
  StreamableHTTPClientTransport,
2851
2936
  UnauthorizedError as UnauthorizedError2
2852
2937
  } from "@modelcontextprotocol/client";
2938
+ var MIXED_AUTH_DISCOVERY_TIMEOUT_MS = 2e3;
2853
2939
  function detectUnauthorized(err, depth = 0) {
2854
2940
  if (!err || depth > 5) return false;
2855
2941
  if (err instanceof UnauthorizedError2) return true;
@@ -2863,6 +2949,11 @@ function detectUnauthorized(err, depth = 0) {
2863
2949
  }
2864
2950
  return false;
2865
2951
  }
2952
+ function isOAuthClientProvider(provider) {
2953
+ return Boolean(
2954
+ provider && "redirectToAuthorization" in provider && typeof provider.redirectToAuthorization === "function" && "tokens" in provider && typeof provider.tokens === "function"
2955
+ );
2956
+ }
2866
2957
  function createMcpProxyFetch(logicalServerUrl, proxyUrl, baseFetch, serverId) {
2867
2958
  const logical = new URL(logicalServerUrl);
2868
2959
  const proxy = proxyUrl.replace(/\/$/, "");
@@ -2888,6 +2979,31 @@ function createMcpProxyFetch(logicalServerUrl, proxyUrl, baseFetch, serverId) {
2888
2979
  );
2889
2980
  };
2890
2981
  }
2982
+ function createDeadlineFetch(baseFetch, deadlineSignal) {
2983
+ return async (input, init) => {
2984
+ const requestSignal = init?.signal;
2985
+ if (!requestSignal) {
2986
+ return baseFetch(input, { ...init, signal: deadlineSignal });
2987
+ }
2988
+ const controller = new AbortController();
2989
+ const abortFromRequest = () => controller.abort(requestSignal.reason);
2990
+ const abortFromDeadline = () => controller.abort(deadlineSignal.reason);
2991
+ if (requestSignal.aborted) abortFromRequest();
2992
+ else
2993
+ requestSignal.addEventListener("abort", abortFromRequest, { once: true });
2994
+ if (deadlineSignal.aborted) abortFromDeadline();
2995
+ else
2996
+ deadlineSignal.addEventListener("abort", abortFromDeadline, {
2997
+ once: true
2998
+ });
2999
+ try {
3000
+ return await baseFetch(input, { ...init, signal: controller.signal });
3001
+ } finally {
3002
+ requestSignal.removeEventListener("abort", abortFromRequest);
3003
+ deadlineSignal.removeEventListener("abort", abortFromDeadline);
3004
+ }
3005
+ };
3006
+ }
2891
3007
  var HttpConnector = class extends BaseConnector {
2892
3008
  baseUrl;
2893
3009
  headers;
@@ -2898,8 +3014,12 @@ var HttpConnector = class extends BaseConnector {
2898
3014
  gatewayUrl;
2899
3015
  serverId;
2900
3016
  reconnectionOptions;
3017
+ detectMixedAuth;
2901
3018
  transportType = null;
2902
3019
  streamableTransport = null;
3020
+ hadAccessTokenAtConnect = false;
3021
+ pendingOAuthCompletion = null;
3022
+ authorizationDiscovery = null;
2903
3023
  /**
2904
3024
  * Creates an HTTP connector.
2905
3025
  *
@@ -2930,6 +3050,103 @@ var HttpConnector = class extends BaseConnector {
2930
3050
  };
2931
3051
  this.protocolNegotiation = opts.protocolNegotiation ?? "auto";
2932
3052
  this.reconnectionOptions = opts.reconnectionOptions;
3053
+ this.detectMixedAuth = opts.detectMixedAuth ?? true;
3054
+ }
3055
+ get oauthProvider() {
3056
+ return isOAuthClientProvider(this.opts.authProvider) ? this.opts.authProvider : void 0;
3057
+ }
3058
+ async completeInteractiveAuthorization() {
3059
+ const provider = this.oauthProvider;
3060
+ if (!provider) {
3061
+ throw new Error("No OAuth client provider is configured");
3062
+ }
3063
+ if (!this.pendingOAuthCompletion) {
3064
+ this.pendingOAuthCompletion = completeOAuthFlow(provider, this.baseUrl, {
3065
+ fetchFn: this.customFetch,
3066
+ finishAuthorization: async (code, iss) => {
3067
+ const transport = this.streamableTransport;
3068
+ if (!transport) {
3069
+ throw new Error("OAuth transport is no longer connected");
3070
+ }
3071
+ await transport.finishAuth(code, iss);
3072
+ }
3073
+ }).then(() => {
3074
+ if (this.authorizationCache) {
3075
+ this.authorizationCache = {
3076
+ ...this.authorizationCache,
3077
+ authenticated: true
3078
+ };
3079
+ }
3080
+ }).finally(() => {
3081
+ this.pendingOAuthCompletion = null;
3082
+ });
3083
+ }
3084
+ await this.pendingOAuthCompletion;
3085
+ }
3086
+ async executeRequest(operation) {
3087
+ try {
3088
+ return await operation();
3089
+ } catch (error) {
3090
+ const provider = this.oauthProvider;
3091
+ if (!provider || provider.preventAutoAuth === true || !isOAuthInteractionRequired(error)) {
3092
+ throw error;
3093
+ }
3094
+ await this.completeInteractiveAuthorization();
3095
+ return operation();
3096
+ }
3097
+ }
3098
+ /** Authenticate an already-connected server without requiring a 401 first. */
3099
+ async authenticate() {
3100
+ if (!this.connected || !this.streamableTransport) {
3101
+ throw new Error("MCP client is not connected");
3102
+ }
3103
+ await this.completeInteractiveAuthorization();
3104
+ }
3105
+ async discoverAuthorization() {
3106
+ if (!this.detectMixedAuth || !this.oauthProvider || this.hadAccessTokenAtConnect) {
3107
+ return this.authorizationCache;
3108
+ }
3109
+ if (this.authorizationDiscovery) return this.authorizationDiscovery;
3110
+ this.authorizationDiscovery = this.discoverMixedAuthorization();
3111
+ return this.authorizationDiscovery;
3112
+ }
3113
+ async discoverMixedAuthorization() {
3114
+ const controller = new AbortController();
3115
+ let timeout;
3116
+ const discoveryTimeout = new Promise((_, reject) => {
3117
+ timeout = setTimeout(() => {
3118
+ const error = new Error(
3119
+ `Mixed-auth metadata discovery timed out after ${MIXED_AUTH_DISCOVERY_TIMEOUT_MS}ms`
3120
+ );
3121
+ controller.abort(error);
3122
+ reject(error);
3123
+ }, MIXED_AUTH_DISCOVERY_TIMEOUT_MS);
3124
+ });
3125
+ const baseFetch = this.customFetch ?? globalThis.fetch.bind(globalThis);
3126
+ try {
3127
+ const metadata = await Promise.race([
3128
+ discoverOAuthProtectedResourceMetadata(
3129
+ this.baseUrl,
3130
+ { protocolVersion: this.negotiatedProtocolVersion },
3131
+ createDeadlineFetch(baseFetch, controller.signal)
3132
+ ),
3133
+ discoveryTimeout
3134
+ ]);
3135
+ this.authorizationCache = {
3136
+ mode: "mixed",
3137
+ authenticated: false,
3138
+ ...metadata.resource ? { resource: metadata.resource } : {},
3139
+ ...metadata.scopes_supported ? { scopesSupported: [...metadata.scopes_supported] } : {}
3140
+ };
3141
+ logger.info(
3142
+ "OAuth protected-resource metadata found after anonymous connection; server uses mixed auth"
3143
+ );
3144
+ } catch (error) {
3145
+ logger.debug("Mixed-auth metadata was not discovered:", error);
3146
+ } finally {
3147
+ if (timeout) clearTimeout(timeout);
3148
+ }
3149
+ return this.authorizationCache;
2933
3150
  }
2934
3151
  buildClientOptions() {
2935
3152
  return {
@@ -3036,6 +3253,16 @@ var HttpConnector = class extends BaseConnector {
3036
3253
  }
3037
3254
  const baseUrl = this.baseUrl;
3038
3255
  logger.debug(`Connecting to MCP implementation via HTTP: ${baseUrl}`);
3256
+ const oauthProvider = this.oauthProvider;
3257
+ if (oauthProvider) {
3258
+ try {
3259
+ this.hadAccessTokenAtConnect = Boolean(
3260
+ (await oauthProvider.tokens())?.access_token
3261
+ );
3262
+ } catch {
3263
+ this.hadAccessTokenAtConnect = false;
3264
+ }
3265
+ }
3039
3266
  try {
3040
3267
  await this.connectWithStreamableHttp(baseUrl);
3041
3268
  logger.debug("\u2705 Successfully connected via streamable HTTP");
@@ -3306,6 +3533,7 @@ var HttpConnector = class extends BaseConnector {
3306
3533
  }
3307
3534
  }
3308
3535
  await super.cleanupResources();
3536
+ this.authorizationDiscovery = null;
3309
3537
  }
3310
3538
  };
3311
3539
 
@@ -3387,6 +3615,7 @@ function createConnectorFromConfig(serverConfig, connectorOptions) {
3387
3615
  fetch: serverConfig.fetch,
3388
3616
  authToken: serverConfig.authToken,
3389
3617
  authProvider: serverConfig.authProvider,
3618
+ detectMixedAuth: serverConfig.detectMixedAuth,
3390
3619
  protocolNegotiation: serverConfig.protocolNegotiation,
3391
3620
  timeout: serverConfig.timeout,
3392
3621
  roots: serverConfig.roots,
@@ -3404,6 +3633,7 @@ import fs from "fs";
3404
3633
  import path from "path";
3405
3634
 
3406
3635
  // src/core/base.ts
3636
+ init_flow();
3407
3637
  init_logging();
3408
3638
 
3409
3639
  // src/core/skills.ts
@@ -3636,6 +3866,18 @@ var MCPConnection = class {
3636
3866
  get serverInfo() {
3637
3867
  return this.connector.serverInfo;
3638
3868
  }
3869
+ /** OAuth state discovered for this connection, when available. */
3870
+ get authorization() {
3871
+ return this.connector.authorization;
3872
+ }
3873
+ /** Discover optional OAuth metadata without delaying MCP readiness. */
3874
+ async discoverAuthorization() {
3875
+ return this.connector.discoverAuthorization();
3876
+ }
3877
+ /** Authenticate an already-connected mixed-auth server. */
3878
+ async authenticate() {
3879
+ await this.connector.authenticate();
3880
+ }
3639
3881
  /**
3640
3882
  * The negotiated protocol era for this session's connection:
3641
3883
  * `"legacy"` (2025-era) or `"modern"` (2026-07-28-era).
@@ -3668,7 +3910,8 @@ var MCPConnection = class {
3668
3910
  ...server ? { server } : {},
3669
3911
  capabilities,
3670
3912
  instructions: this.connector.instructions,
3671
- extensions
3913
+ extensions,
3914
+ ...this.authorization ? { authorization: this.authorization } : {}
3672
3915
  };
3673
3916
  }
3674
3917
  /**
@@ -3899,7 +4142,7 @@ var MCPConnection = class {
3899
4142
  };
3900
4143
 
3901
4144
  // src/core/base.ts
3902
- function isOAuthClientProvider(provider) {
4145
+ function isOAuthClientProvider2(provider) {
3903
4146
  return !!provider && typeof provider === "object" && "redirectUrl" in provider && "clientMetadata" in provider;
3904
4147
  }
3905
4148
  var BaseMCPClient = class {
@@ -4132,7 +4375,7 @@ var BaseMCPClient = class {
4132
4375
  ...serverConfig,
4133
4376
  authProvider: oauthProvider
4134
4377
  };
4135
- } else if ("authProvider" in serverConfig && serverConfig.authProvider && isOAuthClientProvider(serverConfig.authProvider)) {
4378
+ } else if ("authProvider" in serverConfig && serverConfig.authProvider && isOAuthClientProvider2(serverConfig.authProvider)) {
4136
4379
  oauthProvider = serverConfig.authProvider;
4137
4380
  }
4138
4381
  const openSession = async () => {
@@ -5818,6 +6061,7 @@ export {
5818
6061
  createOAuthProvider,
5819
6062
  decline,
5820
6063
  getDefaults,
6064
+ isOAuthInteractionRequired,
5821
6065
  isUnauthorized,
5822
6066
  isVMAvailable,
5823
6067
  loadConfigFile,