From c89384784607b8409799495f00ac6fa22e89142d Mon Sep 17 00:00:00 2001 From: Jeremiah Lowin <153965+jlowin@users.noreply.github.com> Date: Sat, 7 Jun 2025 17:32:50 -0400 Subject: [PATCH 1/3] Respect cache setting, set default to 1 --- src/fastmcp/server/server.py | 7 ++++++- src/fastmcp/settings.py | 4 ++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/fastmcp/server/server.py b/src/fastmcp/server/server.py index 9928ad152..4395a7aca 100644 --- a/src/fastmcp/server/server.py +++ b/src/fastmcp/server/server.py @@ -41,6 +41,7 @@ from starlette.requests import Request from starlette.responses import Response from starlette.routing import BaseRoute, Route +import fastmcp import fastmcp.server import fastmcp.settings from fastmcp.exceptions import NotFoundError @@ -131,6 +132,8 @@ class FastMCP(Generic[LifespanResultT]): tools: list[Tool | Callable[..., Any]] | None = None, **settings: Any, ): + if cache_expiration_seconds is not None: + settings["cache_expiration_seconds"] = cache_expiration_seconds self.settings = fastmcp.settings.ServerSettings(**settings) # If mask_error_details is provided, override the settings value @@ -148,7 +151,9 @@ class FastMCP(Generic[LifespanResultT]): self.tags: set[str] = tags or set() self.dependencies = dependencies self._cache = TimedCache( - expiration=datetime.timedelta(seconds=cache_expiration_seconds or 0) + expiration=datetime.timedelta( + seconds=self.settings.cache_expiration_seconds + ) ) self._mounted_servers: dict[str, MountedServer] = {} self._additional_http_routes: list[BaseRoute] = [] diff --git a/src/fastmcp/settings.py b/src/fastmcp/settings.py index 96939d11c..3c66ad3ae 100644 --- a/src/fastmcp/settings.py +++ b/src/fastmcp/settings.py @@ -170,8 +170,8 @@ class ServerSettings(BaseSettings): ), ] = [] - # cache settings (for checking mounted servers) - cache_expiration_seconds: float = 0 + # cache settings (for getting attributes from servers, used to avoid repeated calls) + cache_expiration_seconds: float = 1 # StreamableHTTP settings json_response: bool = False From 012fccb1ff073c25d15c02b32c65170795330b22 Mon Sep 17 00:00:00 2001 From: Jeremiah Lowin <153965+jlowin@users.noreply.github.com> Date: Sat, 7 Jun 2025 17:36:13 -0400 Subject: [PATCH 2/3] Restore default to zero --- src/fastmcp/settings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fastmcp/settings.py b/src/fastmcp/settings.py index 3c66ad3ae..f39c82ff1 100644 --- a/src/fastmcp/settings.py +++ b/src/fastmcp/settings.py @@ -171,7 +171,7 @@ class ServerSettings(BaseSettings): ] = [] # cache settings (for getting attributes from servers, used to avoid repeated calls) - cache_expiration_seconds: float = 1 + cache_expiration_seconds: float = 0 # StreamableHTTP settings json_response: bool = False From e7672bf0bc9f79f724ece9985a8f15502b15f3d0 Mon Sep 17 00:00:00 2001 From: Jeremiah Lowin <153965+jlowin@users.noreply.github.com> Date: Sat, 7 Jun 2025 17:37:48 -0400 Subject: [PATCH 3/3] Update test_mount.py --- tests/server/test_mount.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/server/test_mount.py b/tests/server/test_mount.py index 090666ccc..97c2efd3e 100644 --- a/tests/server/test_mount.py +++ b/tests/server/test_mount.py @@ -304,6 +304,19 @@ class TestDynamicChanges: tools = await main_app.get_tools() assert "sub_temp_tool" not in tools + async def test_cache_expiration(self): + main_app = FastMCP("MainApp", cache_expiration_seconds=2) + sub_app = FastMCP("SubApp") + tools = await main_app.get_tools() + assert len(tools) == 0 + + @sub_app.tool + def sub_tool(): + return "sub_tool" + + tools = await main_app.get_tools() + assert len(tools) == 0 + class TestResourcesAndTemplates: """Test mounting with resources and resource templates."""