diff --git a/docs/docs.json b/docs/docs.json index 41d3b6886..cb9312699 100644 --- a/docs/docs.json +++ b/docs/docs.json @@ -12,7 +12,7 @@ "decoration": "windows" }, "banner": { - "content": "FastMCP Cloud is coming. [Claim your server](https://fastmcp.link/x0Kyhy2) today!" + "content": "[FastMCP Cloud](https://fastmcp.link/x0Kyhy2) is coming!" }, "colors": { "dark": "#f72585", diff --git a/pyproject.toml b/pyproject.toml index bd89b26d9..c5941af0c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -11,7 +11,6 @@ dependencies = [ "openapi-pydantic>=0.5.1", "rich>=13.9.4", "typer>=0.15.2", - "websockets>=14.0", "authlib>=1.5.2", ] requires-python = ">=3.10" @@ -67,6 +66,9 @@ Homepage = "https://gofastmcp.com" Repository = "https://github.com/jlowin/fastmcp" Documentation = "https://gofastmcp.com" +[project.optional-dependencies] +websockets = ["websockets>=15.0.1"] + [build-system] requires = ["hatchling", "uv-dynamic-versioning>=0.7.0"] diff --git a/src/fastmcp/client/transports.py b/src/fastmcp/client/transports.py index e8a32b018..a2915fbb4 100644 --- a/src/fastmcp/client/transports.py +++ b/src/fastmcp/client/transports.py @@ -27,10 +27,6 @@ from mcp.client.session import ( MessageHandlerFnT, SamplingFnT, ) -from mcp.client.sse import sse_client -from mcp.client.stdio import stdio_client -from mcp.client.streamable_http import streamablehttp_client -from mcp.client.websocket import websocket_client from mcp.server.fastmcp import FastMCP as FastMCP1Server from mcp.shared.memory import create_connected_server_and_client_session from pydantic import AnyUrl @@ -141,6 +137,13 @@ class WSTransport(ClientTransport): async def connect_session( self, **session_kwargs: Unpack[SessionKwargs] ) -> AsyncIterator[ClientSession]: + try: + from mcp.client.websocket import websocket_client + except ImportError: + raise ImportError( + "The websocket transport is not available. Please install fastmcp[websockets] or install the websockets package manually." + ) + async with websocket_client(self.url) as transport: read_stream, write_stream = transport async with ClientSession( @@ -188,6 +191,8 @@ class SSETransport(ClientTransport): async def connect_session( self, **session_kwargs: Unpack[SessionKwargs] ) -> AsyncIterator[ClientSession]: + from mcp.client.sse import sse_client + client_kwargs: dict[str, Any] = {} # load headers from an active HTTP request, if available. This will only be true @@ -255,6 +260,8 @@ class StreamableHttpTransport(ClientTransport): async def connect_session( self, **session_kwargs: Unpack[SessionKwargs] ) -> AsyncIterator[ClientSession]: + from mcp.client.streamable_http import streamablehttp_client + client_kwargs: dict[str, Any] = {} # load headers from an active HTTP request, if available. This will only be true @@ -350,6 +357,8 @@ class StdioTransport(ClientTransport): return async def _connect_task(): + from mcp.client.stdio import stdio_client + async with contextlib.AsyncExitStack() as stack: try: server_params = StdioServerParameters( diff --git a/uv.lock b/uv.lock index 5097b2bcc..4473bfde1 100644 --- a/uv.lock +++ b/uv.lock @@ -437,6 +437,10 @@ dependencies = [ { name = "python-dotenv" }, { name = "rich" }, { name = "typer" }, +] + +[package.optional-dependencies] +websockets = [ { name = "websockets" }, ] @@ -473,8 +477,9 @@ requires-dist = [ { name = "python-dotenv", specifier = ">=1.1.0" }, { name = "rich", specifier = ">=13.9.4" }, { name = "typer", specifier = ">=0.15.2" }, - { name = "websockets", specifier = ">=14.0" }, + { name = "websockets", marker = "extra == 'websockets'", specifier = ">=15.0.1" }, ] +provides-extras = ["websockets"] [package.metadata.requires-dev] dev = [