@mcp-use/client 2.3.1-canary.0 → 2.3.1-canary.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -469,6 +469,9 @@ var init_base = __esm({
469
469
  serverInfoCache = null;
470
470
  authorizationCache;
471
471
  connected = false;
472
+ connectPromise = null;
473
+ disconnectPromise = null;
474
+ disconnectGeneration = 0;
472
475
  opts;
473
476
  notificationHandlers = [];
474
477
  rootsCache = [];
@@ -731,6 +734,54 @@ var init_base = __esm({
731
734
  "setupElicitationHandler: Elicitation handler registered successfully"
732
735
  );
733
736
  }
737
+ /**
738
+ * Establishes the transport connection and creates the SDK client.
739
+ *
740
+ * Coalesces concurrent connection attempts, synchronizes with ongoing
741
+ * disconnections, and guarantees that orphaned processes or transports
742
+ * are not leaked on failure or rapid disconnect.
743
+ *
744
+ * @returns A promise that resolves when the connector is connected.
745
+ */
746
+ async connect() {
747
+ const generation = this.disconnectGeneration;
748
+ while (this.disconnectPromise) {
749
+ await this.disconnectPromise;
750
+ }
751
+ if (generation !== this.disconnectGeneration) {
752
+ throw new Error("Connection cancelled by disconnect");
753
+ }
754
+ if (this.connected) {
755
+ logger.debug("Already connected to MCP implementation");
756
+ return;
757
+ }
758
+ if (this.connectPromise) {
759
+ return this.connectPromise;
760
+ }
761
+ const currentConnect = (async () => {
762
+ try {
763
+ await this.establishTransport();
764
+ if (generation !== this.disconnectGeneration) {
765
+ throw new Error("Connection cancelled by disconnect");
766
+ }
767
+ this.connected = true;
768
+ } catch (err) {
769
+ this.connected = false;
770
+ await this.cleanupResources();
771
+ throw err;
772
+ } finally {
773
+ this.connectPromise = null;
774
+ }
775
+ })();
776
+ this.connectPromise = currentConnect;
777
+ return this.connectPromise;
778
+ }
779
+ /**
780
+ * Subclasses override this method to perform transport-specific connection logic.
781
+ * Default implementation is a no-op for backwards compatibility.
782
+ */
783
+ async establishTransport() {
784
+ }
734
785
  /**
735
786
  * Run one logical MCP operation. HTTP connectors override this host seam to
736
787
  * finish an SDK-started interactive OAuth flow and retry exactly once.
@@ -756,17 +807,42 @@ var init_base = __esm({
756
807
  /**
757
808
  * Disconnects the SDK client and releases transport resources.
758
809
  *
810
+ * Coalesces concurrent calls and coordinates with in-flight connections
811
+ * to ensure no child processes or transports are orphaned.
812
+ *
759
813
  * @returns A promise that resolves after cleanup completes.
760
814
  */
761
815
  async disconnect() {
762
- if (!this.connected) {
816
+ this.disconnectGeneration++;
817
+ if (this.disconnectPromise) {
818
+ return this.disconnectPromise;
819
+ }
820
+ if (!this.connected && !this.connectPromise) {
763
821
  logger.debug("Not connected to MCP implementation");
764
822
  return;
765
823
  }
766
- logger.debug("Disconnecting from MCP implementation");
767
- await this.cleanupResources();
768
- this.connected = false;
769
- logger.debug("Disconnected from MCP implementation");
824
+ const currentDisconnect = (async () => {
825
+ let connectFailed = false;
826
+ try {
827
+ if (this.connectPromise) {
828
+ try {
829
+ await this.connectPromise;
830
+ } catch {
831
+ connectFailed = true;
832
+ }
833
+ }
834
+ if (!connectFailed) {
835
+ logger.debug("Disconnecting from MCP implementation");
836
+ await this.cleanupResources();
837
+ }
838
+ this.connected = false;
839
+ logger.debug("Disconnected from MCP implementation");
840
+ } finally {
841
+ this.disconnectPromise = null;
842
+ }
843
+ })();
844
+ this.disconnectPromise = currentDisconnect;
845
+ return this.disconnectPromise;
770
846
  }
771
847
  /** Whether an SDK client currently exists for this connector. */
772
848
  get isClientConnected() {
@@ -1351,11 +1427,7 @@ var init_stdio = __esm({
1351
1427
  *
1352
1428
  * @returns A promise that resolves after protocol negotiation completes.
1353
1429
  */
1354
- async connect() {
1355
- if (this.connected) {
1356
- logger.debug("Already connected to MCP implementation");
1357
- return;
1358
- }
1430
+ async establishTransport() {
1359
1431
  logger.debug(`Connecting to MCP implementation via stdio: ${this.command}`);
1360
1432
  try {
1361
1433
  const serverParams = {
@@ -1423,7 +1495,6 @@ var init_stdio = __esm({
1423
1495
  );
1424
1496
  await this.client.connect(transport);
1425
1497
  this.setupRoundProgressForwarding();
1426
- this.connected = true;
1427
1498
  this.setupNotificationHandler();
1428
1499
  logger.debug(
1429
1500
  `Successfully connected to MCP implementation: ${this.command}`
@@ -1435,7 +1506,6 @@ var init_stdio = __esm({
1435
1506
  });
1436
1507
  } catch (err) {
1437
1508
  logger.error(`Failed to connect to MCP implementation: ${err}`);
1438
- await this.cleanupResources();
1439
1509
  throw err;
1440
1510
  }
1441
1511
  }
@@ -1527,7 +1597,7 @@ init_connector_telemetry();
1527
1597
  init_logging();
1528
1598
 
1529
1599
  // src/utils/version.ts
1530
- var VERSION = "2.3.1-canary.0";
1600
+ var VERSION = "2.3.1-canary.2";
1531
1601
  function getPackageVersion() {
1532
1602
  return VERSION;
1533
1603
  }
@@ -3272,11 +3342,7 @@ var HttpConnector = class extends BaseConnector {
3272
3342
  * @returns A promise that resolves after protocol negotiation completes.
3273
3343
  * @throws An error with `code: 401` when authentication is required.
3274
3344
  */
3275
- async connect() {
3276
- if (this.connected) {
3277
- logger.debug("Already connected to MCP implementation");
3278
- return;
3279
- }
3345
+ async establishTransport() {
3280
3346
  const baseUrl = this.baseUrl;
3281
3347
  logger.debug(`Connecting to MCP implementation via HTTP: ${baseUrl}`);
3282
3348
  const oauthProvider = this.oauthProvider;
@@ -3295,7 +3361,6 @@ var HttpConnector = class extends BaseConnector {
3295
3361
  } catch (err) {
3296
3362
  logger.debug("Streamable HTTP connect failed", err);
3297
3363
  const { fallbackReason, is401Error, httpStatusCode } = this.classifyStreamableHttpFailure(err);
3298
- await this.cleanupResources();
3299
3364
  if (is401Error) {
3300
3365
  logger.info("Authentication required");
3301
3366
  const authError = new Error("Authentication required");
@@ -3469,7 +3534,6 @@ var HttpConnector = class extends BaseConnector {
3469
3534
  }
3470
3535
  }
3471
3536
  };
3472
- this.connected = true;
3473
3537
  this.transportType = "streamable-http";
3474
3538
  logger.debug(
3475
3539
  `Successfully connected to MCP implementation via streamable HTTP: ${baseUrl}`
@@ -5426,11 +5490,7 @@ var CodeModeConnector = class extends BaseConnector {
5426
5490
  this.connected = true;
5427
5491
  this._tools = this._createToolsList();
5428
5492
  }
5429
- async connect() {
5430
- this.connected = true;
5431
- }
5432
- async disconnect() {
5433
- this.connected = false;
5493
+ async establishTransport() {
5434
5494
  }
5435
5495
  get publicIdentifier() {
5436
5496
  return { name: "code_mode", version: "1.0.0" };