Merge branch 'main' into clientconfig

This commit is contained in:
Jeremiah Lowin 2025-05-22 11:23:52 -04:00
commit 451fc3bfc2
5 changed files with 49 additions and 14 deletions

View file

@ -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`.

View file

@ -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.

View file

@ -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.
</Warning>
## 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):

View file

@ -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

View file

@ -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)