From a392f78d0760f57aab00d6b1e27e539081018deb Mon Sep 17 00:00:00 2001 From: Jeremiah Lowin <153965+jlowin@users.noreply.github.com> Date: Tue, 27 May 2025 08:43:31 -0400 Subject: [PATCH] Add global setting --- src/fastmcp/client/client.py | 49 ++++++++++++++++++------------------ src/fastmcp/settings.py | 8 ++++++ 2 files changed, 33 insertions(+), 24 deletions(-) diff --git a/src/fastmcp/client/client.py b/src/fastmcp/client/client.py index 7e8c106e8..b177b950a 100644 --- a/src/fastmcp/client/client.py +++ b/src/fastmcp/client/client.py @@ -9,6 +9,7 @@ from exceptiongroup import catch from mcp import ClientSession from pydantic import AnyUrl +import fastmcp from fastmcp.client.logging import ( LogHandler, MessageHandler, @@ -45,8 +46,8 @@ class Client: MCP client that delegates connection management to a Transport instance. The Client class is responsible for MCP protocol logic, while the Transport - handles connection establishment and management. Client provides methods - for working with resources, prompts, tools and other MCP capabilities. + handles connection establishment and management. Client provides methods for + working with resources, prompts, tools and other MCP capabilities. Args: transport: Connection source specification, which can be: @@ -57,25 +58,23 @@ class Client: - MCPConfig: MCP server configuration - dict: Transport configuration roots: Optional RootsList or RootsHandler for filesystem access - sampling_handler: Optional handler for sampling requests - log_handler: Optional handler for log messages - message_handler: Optional handler for protocol messages - progress_handler: Optional handler for progress notifications - timeout: Optional timeout for requests (seconds or timedelta) - init_timeout: Optional timeout for initial connection (seconds or - timedelta) + sampling_handler: Optional handler for sampling requests log_handler: + Optional handler for log messages message_handler: Optional handler for + protocol messages progress_handler: Optional handler for progress + notifications timeout: Optional timeout for requests (seconds or + timedelta) init_timeout: Optional timeout for initial connection + (seconds or timedelta). Set to 0 to disable. If None, uses the value + in the FastMCP global settings. Examples: - ```python - # Connect to FastMCP server - client = Client("http://localhost:8080") + ```python # Connect to FastMCP server client = + Client("http://localhost:8080") async with client: - # List available resources - resources = await client.list_resources() + # List available resources resources = await client.list_resources() - # Call a tool - result = await client.call_tool("my_tool", {"param": "value"}) + # Call a tool result = await client.call_tool("my_tool", {"param": + "value"}) ``` """ @@ -95,7 +94,7 @@ class Client: message_handler: MessageHandler | None = None, progress_handler: ProgressHandler | None = None, timeout: datetime.timedelta | float | int | None = None, - init_timeout: datetime.timedelta | float | int = 1, + init_timeout: datetime.timedelta | float | int | None = None, ): self.transport = infer_transport(transport) self._session: ClientSession | None = None @@ -114,14 +113,16 @@ class Client: if isinstance(timeout, int | float): timeout = datetime.timedelta(seconds=timeout) - if isinstance(init_timeout, int): - self._init_timeout = float(init_timeout) - elif isinstance(init_timeout, datetime.timedelta): - self._init_timeout = float(init_timeout.total_seconds()) - elif isinstance(init_timeout, float): - self._init_timeout = init_timeout + # handle init handshake timeout + if init_timeout is None: + init_timeout = fastmcp.settings.settings.client_init_timeout + if isinstance(init_timeout, datetime.timedelta): + init_timeout = init_timeout.total_seconds() + elif not init_timeout: + init_timeout = None else: - raise ValueError("init_timeout must be int, float or datetime.timedelta") + init_timeout = float(init_timeout) + self._init_timeout = init_timeout self._session_kwargs: SessionKwargs = { "sampling_callback": None, diff --git a/src/fastmcp/settings.py b/src/fastmcp/settings.py index 662b0db6f..30b7a7461 100644 --- a/src/fastmcp/settings.py +++ b/src/fastmcp/settings.py @@ -87,6 +87,14 @@ class Settings(BaseSettings): ), ] = False + client_init_timeout: Annotated[ + float | None, + Field( + default=1, + description="The timeout for the client's initialization handshake, in seconds. Set to None or 0 to disable.", + ), + ] = None + @model_validator(mode="after") def setup_logging(self) -> Self: """Finalize the settings."""