diff --git a/docs/clients/client.mdx b/docs/clients/client.mdx index 7c1455712..70c47bfa9 100644 --- a/docs/clients/client.mdx +++ b/docs/clients/client.mdx @@ -37,7 +37,7 @@ Clients must be initialized with a `transport`. You can either provide an alread The following inference rules are used to determine the appropriate `ClientTransport` based on the input type: 1. **`ClientTransport` Instance**: If you provide an already instantiated transport object, it's used directly. -2. **`FastMCP` Instance**: Creates a `FastMCPTransport` for efficient in-memory communication (ideal for testing). +2. **`FastMCP` Instance**: Creates a `FastMCPTransport` for efficient in-memory communication (ideal for testing). This also works with a **FastMCP 1.0 server** created via `mcp.server.fastmcp.FastMCP`. 3. **`Path` or `str` pointing to an existing file**: * If it ends with `.py`: Creates a `PythonStdioTransport` to run the script using `python`. * If it ends with `.js`: Creates a `NodeStdioTransport` to run the script using `node`. diff --git a/docs/clients/transports.mdx b/docs/clients/transports.mdx index 958cafcae..b89f46884 100644 --- a/docs/clients/transports.mdx +++ b/docs/clients/transports.mdx @@ -290,8 +290,8 @@ asyncio.run(main()) ### FastMCP Transport - **Class:** `fastmcp.client.transports.FastMCPTransport` -- **Inferred From:** An instance of `fastmcp.server.FastMCP` -- **Use Case:** Connecting directly to a `FastMCP` server instance in the same Python process +- **Inferred From:** An instance of `fastmcp.server.FastMCP` or a **FastMCP 1.0 server** (`mcp.server.fastmcp.FastMCP`) +- **Use Case:** Connecting directly to a FastMCP server instance in the same Python process This is extremely useful for testing your FastMCP servers. diff --git a/docs/getting-started/installation.mdx b/docs/getting-started/installation.mdx index 46552e5c4..aaff866e3 100644 --- a/docs/getting-started/installation.mdx +++ b/docs/getting-started/installation.mdx @@ -60,6 +60,20 @@ mcp = FastMCP("My MCP Server") Prior to `fastmcp==2.3.0` and `mcp==1.8.0`, the 2.x API always mirrored the 1.0 API. However, as the projects diverge, this can not be guaranteed. You may see deprecation warnings if you attempt to use 1.0 APIs in FastMCP 2.x. Please refer to this documentation for details on new capabilities. +## Versioning and Breaking Changes + +While we make every effort not to introduce backwards-incompatible changes to our public APIs and behavior, FastMCP exists in a rapidly evolving MCP landscape. We're committed to bringing the most cutting-edge features to our users, which occasionally necessitates changes to existing functionality. + +As a practice, breaking changes will only occur on minor version changes (e.g., 2.3.x to 2.4.0). A minor version change indicates either: +- A significant new feature set that warrants a new minor version +- Introducing breaking changes that may affect behavior on upgrade + +For users concerned about stability in production environments, we recommend pinning FastMCP to a specific version in your dependencies. + +Whenever possible, FastMCP will issue deprecation warnings when users attempt to use APIs that are either deprecated or destined for future removal. These warnings will be maintained for at least 1 minor version release, and may be maintained longer. + +Note that the "public API" includes the core functionality of the `FastMCP` server and its methods. It does not include private methods or objects that are stored as private attributes, as we do not expect users to rely on those implementation details. + ## Installing for Development If you plan to contribute to FastMCP, you should begin by cloning the repository and using uv to install all dependencies (development dependencies are installed automatically): diff --git a/src/fastmcp/client/transports.py b/src/fastmcp/client/transports.py index e2e8a7eb5..f82b238d0 100644 --- a/src/fastmcp/client/transports.py +++ b/src/fastmcp/client/transports.py @@ -19,6 +19,7 @@ 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 from typing_extensions import Unpack @@ -448,15 +449,21 @@ class NpxStdioTransport(StdioTransport): class FastMCPTransport(ClientTransport): - """ - Special transport for in-memory connections to an MCP server. + """In-memory transport for FastMCP servers. - This is particularly useful for testing or when client and server - are in the same process. + This transport connects directly to a FastMCP server instance in the same + Python process. It works with both FastMCP 2.x servers and FastMCP 1.0 + servers from the low-level MCP SDK. This is particularly useful for unit + tests or scenarios where client and server run in the same runtime. """ - def __init__(self, mcp: FastMCPServer): - self.server = mcp # Can be FastMCP or MCPServer + def __init__(self, mcp: FastMCPServer | FastMCP1Server): + """Initialize a FastMCPTransport from a FastMCP server instance.""" + + # Accept both FastMCP 2.x and FastMCP 1.0 servers. Both expose a + # ``_mcp_server`` attribute pointing to the underlying MCP server + # implementation, so we can treat them identically. + self.server = mcp @contextlib.asynccontextmanager async def connect_session( @@ -562,6 +569,7 @@ class MCPConfigTransport(ClientTransport): def infer_transport( transport: ClientTransport | FastMCPServer + | FastMCP1Server | AnyUrl | Path | MCPConfig @@ -577,7 +585,7 @@ def infer_transport( The function supports these input types: - ClientTransport: Used directly without modification - - FastMCPServer: Creates an in-memory FastMCPTransport + - FastMCPServer or FastMCP1Server: Creates an in-memory FastMCPTransport - Path or str (file path): Creates PythonStdioTransport (.py) or NodeStdioTransport (.js) - AnyUrl or str (URL): Creates StreamableHttpTransport (default) or SSETransport (for /sse endpoints) - MCPConfig or dict: Creates MCPConfigTransport, potentially connecting to multiple servers @@ -614,8 +622,8 @@ def infer_transport( if isinstance(transport, ClientTransport): return transport - # the transport is a FastMCP server - elif isinstance(transport, FastMCPServer): + # the transport is a FastMCP server (2.x or 1.0) + elif isinstance(transport, FastMCPServer | FastMCP1Server): inferred_transport = FastMCPTransport(mcp=transport) # the transport is a path to a script diff --git a/tests/client/test_client.py b/tests/client/test_client.py index e85ca4fc5..71625d45e 100644 --- a/tests/client/test_client.py +++ b/tests/client/test_client.py @@ -685,7 +685,7 @@ class TestInferTransport: with pytest.raises(ValueError, match="No MCP servers defined in the config"): MCPConfigTransport(config=config) - def test_infer_composite_client(config): + def test_infer_composite_client(self): config = { "mcpServers": { "local": { @@ -701,4 +701,17 @@ class TestInferTransport: transport = infer_transport(config) assert isinstance(transport, MCPConfigTransport) assert isinstance(transport.transport, FastMCPTransport) - assert len(transport.transport.server._mounted_servers) == 2 + assert len(cast(FastMCP, transport.transport.server)._mounted_servers) == 2 + + def test_infer_fastmcp_server(self, fastmcp_server): + """FastMCP server instances should infer to FastMCPTransport.""" + transport = infer_transport(fastmcp_server) + assert isinstance(transport, FastMCPTransport) + + def test_infer_fastmcp_v1_server(self): + """FastMCP 1.0 server instances should infer to FastMCPTransport.""" + from mcp.server.fastmcp import FastMCP as FastMCP1 + + server = FastMCP1() + transport = infer_transport(server) + assert isinstance(transport, FastMCPTransport)