fastmcp 4.22.6 → 4.22.7

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.
@@ -684,77 +684,12 @@ var FastMCPSession = class extends FastMCPSessionEventEmitter {
684
684
  throw new UnexpectedStateError("Server is already connected");
685
685
  }
686
686
  this.#connectionState = "connecting";
687
+ const streamableHttp = !this.#stateless && isStreamableHttpTransport(transport);
687
688
  try {
688
689
  await this.#server.connect(transport);
689
- if (!this.#stateless) {
690
- let attempt = 0;
691
- const maxAttempts = 10;
692
- const retryDelay = 100;
693
- while (attempt++ < maxAttempts) {
694
- const capabilities = this.#server.getClientCapabilities();
695
- if (capabilities) {
696
- this.#clientCapabilities = capabilities;
697
- break;
698
- }
699
- await _promises3.setTimeout.call(void 0, retryDelay);
700
- }
701
- if (!this.#clientCapabilities) {
702
- this.#logger.warn(
703
- `[FastMCP warning] could not infer client capabilities after ${maxAttempts} attempts. Connection may be unstable.`
704
- );
705
- }
690
+ if (!streamableHttp) {
691
+ await this.#setUpSession(false);
706
692
  }
707
- if (_optionalChain([this, 'access', _12 => _12.#rootsConfig, 'optionalAccess', _13 => _13.enabled]) !== false && _optionalChain([this, 'access', _14 => _14.#clientCapabilities, 'optionalAccess', _15 => _15.roots, 'optionalAccess', _16 => _16.listChanged]) && typeof this.#server.listRoots === "function") {
708
- try {
709
- const roots = await this.#server.listRoots();
710
- this.#roots = _optionalChain([roots, 'optionalAccess', _17 => _17.roots]) || [];
711
- } catch (e) {
712
- if (e instanceof _typesjs.McpError && e.code === _typesjs.ErrorCode.MethodNotFound) {
713
- this.#logger.debug(
714
- "[FastMCP debug] listRoots method not supported by client"
715
- );
716
- } else {
717
- this.#logger.error(
718
- `[FastMCP error] received error listing roots.
719
-
720
- ${e instanceof Error ? e.stack : JSON.stringify(e)}`
721
- );
722
- }
723
- }
724
- }
725
- if (this.#clientCapabilities) {
726
- const pingConfig = this.#getPingConfig();
727
- if (pingConfig.enabled) {
728
- this.#pingInterval = setInterval(async () => {
729
- if (this.#pingInFlight) {
730
- return;
731
- }
732
- this.#pingInFlight = true;
733
- try {
734
- await this.#server.ping();
735
- } catch (e4) {
736
- const logLevel = pingConfig.logLevel;
737
- if (logLevel === "debug") {
738
- this.#logger.debug("[FastMCP debug] server ping failed");
739
- } else if (logLevel === "warning") {
740
- this.#logger.warn(
741
- "[FastMCP warning] server is not responding to ping"
742
- );
743
- } else if (logLevel === "error") {
744
- this.#logger.error(
745
- "[FastMCP error] server is not responding to ping"
746
- );
747
- } else {
748
- this.#logger.info("[FastMCP info] server ping failed");
749
- }
750
- } finally {
751
- this.#pingInFlight = false;
752
- }
753
- }, pingConfig.intervalMs);
754
- }
755
- }
756
- this.#connectionState = "ready";
757
- this.emit("ready");
758
693
  } catch (error) {
759
694
  this.#connectionState = "error";
760
695
  const errorEvent = {
@@ -763,6 +698,18 @@ ${e instanceof Error ? e.stack : JSON.stringify(e)}`
763
698
  this.emit("error", errorEvent);
764
699
  throw error;
765
700
  }
701
+ if (streamableHttp) {
702
+ this.#setUpSession(true).catch((error) => {
703
+ this.#connectionState = "error";
704
+ if (this.listenerCount("error") > 0) {
705
+ this.emit("error", {
706
+ error: error instanceof Error ? error : new Error(String(error))
707
+ });
708
+ } else {
709
+ this.#logger.error("[FastMCP error] session setup failed", error);
710
+ }
711
+ });
712
+ }
766
713
  }
767
714
  promptsListChanged(prompts) {
768
715
  if (!this.#canRefresh("prompts")) {
@@ -931,7 +878,7 @@ ${error instanceof Error ? error.stack : JSON.stringify(error)}`
931
878
  },
932
879
  elicit: (params, options) => this.#server.elicitInput(params, options),
933
880
  log: this.#createLog(),
934
- requestId: typeof _optionalChain([meta, 'optionalAccess', _18 => _18.requestId]) === "string" ? meta.requestId : void 0,
881
+ requestId: typeof _optionalChain([meta, 'optionalAccess', _12 => _12.requestId]) === "string" ? meta.requestId : void 0,
935
882
  session: this.#auth,
936
883
  sessionId: this.sessionId
937
884
  };
@@ -953,8 +900,8 @@ ${error instanceof Error ? error.stack : JSON.stringify(error)}`
953
900
  };
954
901
  }
955
902
  #formatSchemaIssues(issues) {
956
- return _optionalChain([this, 'access', _19 => _19.#utils, 'optionalAccess', _20 => _20.formatInvalidParamsErrorMessage]) ? this.#utils.formatInvalidParamsErrorMessage(issues) : issues.map((issue) => {
957
- const path = _optionalChain([issue, 'access', _21 => _21.path, 'optionalAccess', _22 => _22.join, 'call', _23 => _23(".")]) || "root";
903
+ return _optionalChain([this, 'access', _13 => _13.#utils, 'optionalAccess', _14 => _14.formatInvalidParamsErrorMessage]) ? this.#utils.formatInvalidParamsErrorMessage(issues) : issues.map((issue) => {
904
+ const path = _optionalChain([issue, 'access', _15 => _15.path, 'optionalAccess', _16 => _16.join, 'call', _17 => _17(".")]) || "root";
958
905
  return `${path}: ${issue.message}`;
959
906
  }).join(", ");
960
907
  }
@@ -967,6 +914,52 @@ ${error instanceof Error ? error.stack : JSON.stringify(error)}`
967
914
  logLevel: pingConfig.logLevel || "debug"
968
915
  };
969
916
  }
917
+ /**
918
+ * Fetches the client's roots if it advertised `roots.listChanged`.
919
+ *
920
+ * Over Streamable HTTP a server-initiated request travels on the client's
921
+ * standalone GET stream, which the client opens only after initialization,
922
+ * and the transport drops a request sent before that. So there each attempt
923
+ * is bounded and retried, and the result is announced with `rootsChanged`.
924
+ */
925
+ async #loadRoots(streamableHttp) {
926
+ if (_optionalChain([this, 'access', _18 => _18.#rootsConfig, 'optionalAccess', _19 => _19.enabled]) === false || !_optionalChain([this, 'access', _20 => _20.#clientCapabilities, 'optionalAccess', _21 => _21.roots, 'optionalAccess', _22 => _22.listChanged]) || typeof this.#server.listRoots !== "function") {
927
+ return;
928
+ }
929
+ const maxAttempts = streamableHttp ? 5 : 1;
930
+ for (let attempt = 1; ; attempt++) {
931
+ try {
932
+ const roots = await this.#server.listRoots(
933
+ void 0,
934
+ streamableHttp ? { timeout: 1e3 } : void 0
935
+ );
936
+ this.#roots = _optionalChain([roots, 'optionalAccess', _23 => _23.roots]) || [];
937
+ if (streamableHttp) {
938
+ this.emit("rootsChanged", { roots: this.#roots });
939
+ }
940
+ return;
941
+ } catch (e) {
942
+ if (this.#connectionState === "closed") {
943
+ return;
944
+ }
945
+ if (attempt < maxAttempts && e instanceof _typesjs.McpError && e.code === _typesjs.ErrorCode.RequestTimeout) {
946
+ continue;
947
+ }
948
+ if (e instanceof _typesjs.McpError && e.code === _typesjs.ErrorCode.MethodNotFound) {
949
+ this.#logger.debug(
950
+ "[FastMCP debug] listRoots method not supported by client"
951
+ );
952
+ } else {
953
+ this.#logger.error(
954
+ `[FastMCP error] received error listing roots.
955
+
956
+ ${e instanceof Error ? e.stack : JSON.stringify(e)}`
957
+ );
958
+ }
959
+ return;
960
+ }
961
+ }
962
+ }
970
963
  /**
971
964
  * `sendLoggingMessage` rejects once the client has hung up, and these four
972
965
  * callers are synchronous, so the rejection has nowhere to go. Swallow it the
@@ -991,6 +984,67 @@ ${error instanceof Error ? error.stack : JSON.stringify(error)}`
991
984
  );
992
985
  });
993
986
  }
987
+ async #setUpSession(streamableHttp) {
988
+ if (!this.#stateless) {
989
+ let attempt = 0;
990
+ const maxAttempts = 10;
991
+ const retryDelay = 100;
992
+ while (attempt++ < maxAttempts) {
993
+ const capabilities = this.#server.getClientCapabilities();
994
+ if (capabilities) {
995
+ this.#clientCapabilities = capabilities;
996
+ break;
997
+ }
998
+ await _promises3.setTimeout.call(void 0, retryDelay);
999
+ }
1000
+ if (!this.#clientCapabilities) {
1001
+ this.#logger.warn(
1002
+ `[FastMCP warning] could not infer client capabilities after ${maxAttempts} attempts. Connection may be unstable.`
1003
+ );
1004
+ }
1005
+ }
1006
+ if (this.#connectionState === "closed") {
1007
+ return;
1008
+ }
1009
+ if (streamableHttp) {
1010
+ void this.#loadRoots(true);
1011
+ } else {
1012
+ await this.#loadRoots(false);
1013
+ }
1014
+ if (this.#clientCapabilities) {
1015
+ const pingConfig = this.#getPingConfig();
1016
+ if (pingConfig.enabled) {
1017
+ this.#pingInterval = setInterval(async () => {
1018
+ if (this.#pingInFlight) {
1019
+ return;
1020
+ }
1021
+ this.#pingInFlight = true;
1022
+ try {
1023
+ await this.#server.ping();
1024
+ } catch (e4) {
1025
+ const logLevel = pingConfig.logLevel;
1026
+ if (logLevel === "debug") {
1027
+ this.#logger.debug("[FastMCP debug] server ping failed");
1028
+ } else if (logLevel === "warning") {
1029
+ this.#logger.warn(
1030
+ "[FastMCP warning] server is not responding to ping"
1031
+ );
1032
+ } else if (logLevel === "error") {
1033
+ this.#logger.error(
1034
+ "[FastMCP error] server is not responding to ping"
1035
+ );
1036
+ } else {
1037
+ this.#logger.info("[FastMCP info] server ping failed");
1038
+ }
1039
+ } finally {
1040
+ this.#pingInFlight = false;
1041
+ }
1042
+ }, pingConfig.intervalMs);
1043
+ }
1044
+ }
1045
+ this.#connectionState = "ready";
1046
+ this.emit("ready");
1047
+ }
994
1048
  /**
995
1049
  * Periodically writes to the response stream of an in-flight tool call, so an
996
1050
  * idle-connection timeout (proxy, load balancer) does not close it while a
@@ -1667,6 +1721,9 @@ function convertObjectToSnakeCase(obj) {
1667
1721
  }
1668
1722
  return result;
1669
1723
  }
1724
+ function isStreamableHttpTransport(transport) {
1725
+ return "handleRequest" in transport && typeof transport.handleRequest === "function";
1726
+ }
1670
1727
  function joinPaths(basePath, path) {
1671
1728
  return `${basePath}${normalizePath(path)}`;
1672
1729
  }
@@ -3066,4 +3123,4 @@ var FastMCP = class extends FastMCPEventEmitter {
3066
3123
 
3067
3124
 
3068
3125
  exports.DiscoveryDocumentCache = DiscoveryDocumentCache; exports.jsonSchemaAdapter = jsonSchemaAdapter; exports.MEDIA_FETCH_TIMEOUT_MS = MEDIA_FETCH_TIMEOUT_MS; exports.imageContent = imageContent; exports.audioContent = audioContent; exports.FastMCPError = FastMCPError; exports.SessionError = SessionError; exports.UnexpectedStateError = UnexpectedStateError; exports.UserError = UserError; exports.ServerState = ServerState; exports.FastMCPSession = FastMCPSession; exports.FastMCP = FastMCP;
3069
- //# sourceMappingURL=chunk-QJIFKZYZ.cjs.map
3126
+ //# sourceMappingURL=chunk-QICOIGCH.cjs.map