Jeremiah Lowin commited on
Commit
d820cb7
·
2 Parent(s): 7445afaf80d248

Merge branch 'main' into clientconfig

Browse files
docs/clients/client.mdx CHANGED
@@ -37,7 +37,7 @@ Clients must be initialized with a `transport`. You can either provide an alread
37
  The following inference rules are used to determine the appropriate `ClientTransport` based on the input type:
38
 
39
  1. **`ClientTransport` Instance**: If you provide an already instantiated transport object, it's used directly.
40
- 2. **`FastMCP` Instance**: Creates a `FastMCPTransport` for efficient in-memory communication (ideal for testing).
41
  3. **`Path` or `str` pointing to an existing file**:
42
  * If it ends with `.py`: Creates a `PythonStdioTransport` to run the script using `python`.
43
  * If it ends with `.js`: Creates a `NodeStdioTransport` to run the script using `node`.
 
37
  The following inference rules are used to determine the appropriate `ClientTransport` based on the input type:
38
 
39
  1. **`ClientTransport` Instance**: If you provide an already instantiated transport object, it's used directly.
40
+ 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`.
41
  3. **`Path` or `str` pointing to an existing file**:
42
  * If it ends with `.py`: Creates a `PythonStdioTransport` to run the script using `python`.
43
  * If it ends with `.js`: Creates a `NodeStdioTransport` to run the script using `node`.
docs/clients/transports.mdx CHANGED
@@ -290,8 +290,8 @@ asyncio.run(main())
290
  ### FastMCP Transport
291
 
292
  - **Class:** `fastmcp.client.transports.FastMCPTransport`
293
- - **Inferred From:** An instance of `fastmcp.server.FastMCP`
294
- - **Use Case:** Connecting directly to a `FastMCP` server instance in the same Python process
295
 
296
  This is extremely useful for testing your FastMCP servers.
297
 
 
290
  ### FastMCP Transport
291
 
292
  - **Class:** `fastmcp.client.transports.FastMCPTransport`
293
+ - **Inferred From:** An instance of `fastmcp.server.FastMCP` or a **FastMCP 1.0 server** (`mcp.server.fastmcp.FastMCP`)
294
+ - **Use Case:** Connecting directly to a FastMCP server instance in the same Python process
295
 
296
  This is extremely useful for testing your FastMCP servers.
297
 
docs/getting-started/installation.mdx CHANGED
@@ -60,6 +60,20 @@ mcp = FastMCP("My MCP Server")
60
  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.
61
  </Warning>
62
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
63
  ## Installing for Development
64
 
65
  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):
 
60
  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.
61
  </Warning>
62
 
63
+ ## Versioning and Breaking Changes
64
+
65
+ 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.
66
+
67
+ 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:
68
+ - A significant new feature set that warrants a new minor version
69
+ - Introducing breaking changes that may affect behavior on upgrade
70
+
71
+ For users concerned about stability in production environments, we recommend pinning FastMCP to a specific version in your dependencies.
72
+
73
+ 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.
74
+
75
+ 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.
76
+
77
  ## Installing for Development
78
 
79
  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):
src/fastmcp/client/transports.py CHANGED
@@ -19,6 +19,7 @@ from mcp.client.sse import sse_client
19
  from mcp.client.stdio import stdio_client
20
  from mcp.client.streamable_http import streamablehttp_client
21
  from mcp.client.websocket import websocket_client
 
22
  from mcp.shared.memory import create_connected_server_and_client_session
23
  from pydantic import AnyUrl
24
  from typing_extensions import Unpack
@@ -448,15 +449,21 @@ class NpxStdioTransport(StdioTransport):
448
 
449
 
450
  class FastMCPTransport(ClientTransport):
451
- """
452
- Special transport for in-memory connections to an MCP server.
453
 
454
- This is particularly useful for testing or when client and server
455
- are in the same process.
 
 
456
  """
457
 
458
- def __init__(self, mcp: FastMCPServer):
459
- self.server = mcp # Can be FastMCP or MCPServer
 
 
 
 
 
460
 
461
  @contextlib.asynccontextmanager
462
  async def connect_session(
@@ -562,6 +569,7 @@ class MCPConfigTransport(ClientTransport):
562
  def infer_transport(
563
  transport: ClientTransport
564
  | FastMCPServer
 
565
  | AnyUrl
566
  | Path
567
  | MCPConfig
@@ -577,7 +585,7 @@ def infer_transport(
577
 
578
  The function supports these input types:
579
  - ClientTransport: Used directly without modification
580
- - FastMCPServer: Creates an in-memory FastMCPTransport
581
  - Path or str (file path): Creates PythonStdioTransport (.py) or NodeStdioTransport (.js)
582
  - AnyUrl or str (URL): Creates StreamableHttpTransport (default) or SSETransport (for /sse endpoints)
583
  - MCPConfig or dict: Creates MCPConfigTransport, potentially connecting to multiple servers
@@ -614,8 +622,8 @@ def infer_transport(
614
  if isinstance(transport, ClientTransport):
615
  return transport
616
 
617
- # the transport is a FastMCP server
618
- elif isinstance(transport, FastMCPServer):
619
  inferred_transport = FastMCPTransport(mcp=transport)
620
 
621
  # the transport is a path to a script
 
19
  from mcp.client.stdio import stdio_client
20
  from mcp.client.streamable_http import streamablehttp_client
21
  from mcp.client.websocket import websocket_client
22
+ from mcp.server.fastmcp import FastMCP as FastMCP1Server
23
  from mcp.shared.memory import create_connected_server_and_client_session
24
  from pydantic import AnyUrl
25
  from typing_extensions import Unpack
 
449
 
450
 
451
  class FastMCPTransport(ClientTransport):
452
+ """In-memory transport for FastMCP servers.
 
453
 
454
+ This transport connects directly to a FastMCP server instance in the same
455
+ Python process. It works with both FastMCP 2.x servers and FastMCP 1.0
456
+ servers from the low-level MCP SDK. This is particularly useful for unit
457
+ tests or scenarios where client and server run in the same runtime.
458
  """
459
 
460
+ def __init__(self, mcp: FastMCPServer | FastMCP1Server):
461
+ """Initialize a FastMCPTransport from a FastMCP server instance."""
462
+
463
+ # Accept both FastMCP 2.x and FastMCP 1.0 servers. Both expose a
464
+ # ``_mcp_server`` attribute pointing to the underlying MCP server
465
+ # implementation, so we can treat them identically.
466
+ self.server = mcp
467
 
468
  @contextlib.asynccontextmanager
469
  async def connect_session(
 
569
  def infer_transport(
570
  transport: ClientTransport
571
  | FastMCPServer
572
+ | FastMCP1Server
573
  | AnyUrl
574
  | Path
575
  | MCPConfig
 
585
 
586
  The function supports these input types:
587
  - ClientTransport: Used directly without modification
588
+ - FastMCPServer or FastMCP1Server: Creates an in-memory FastMCPTransport
589
  - Path or str (file path): Creates PythonStdioTransport (.py) or NodeStdioTransport (.js)
590
  - AnyUrl or str (URL): Creates StreamableHttpTransport (default) or SSETransport (for /sse endpoints)
591
  - MCPConfig or dict: Creates MCPConfigTransport, potentially connecting to multiple servers
 
622
  if isinstance(transport, ClientTransport):
623
  return transport
624
 
625
+ # the transport is a FastMCP server (2.x or 1.0)
626
+ elif isinstance(transport, FastMCPServer | FastMCP1Server):
627
  inferred_transport = FastMCPTransport(mcp=transport)
628
 
629
  # the transport is a path to a script
tests/client/test_client.py CHANGED
@@ -685,7 +685,7 @@ class TestInferTransport:
685
  with pytest.raises(ValueError, match="No MCP servers defined in the config"):
686
  MCPConfigTransport(config=config)
687
 
688
- def test_infer_composite_client(config):
689
  config = {
690
  "mcpServers": {
691
  "local": {
@@ -701,4 +701,17 @@ class TestInferTransport:
701
  transport = infer_transport(config)
702
  assert isinstance(transport, MCPConfigTransport)
703
  assert isinstance(transport.transport, FastMCPTransport)
704
- assert len(transport.transport.server._mounted_servers) == 2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
685
  with pytest.raises(ValueError, match="No MCP servers defined in the config"):
686
  MCPConfigTransport(config=config)
687
 
688
+ def test_infer_composite_client(self):
689
  config = {
690
  "mcpServers": {
691
  "local": {
 
701
  transport = infer_transport(config)
702
  assert isinstance(transport, MCPConfigTransport)
703
  assert isinstance(transport.transport, FastMCPTransport)
704
+ assert len(cast(FastMCP, transport.transport.server)._mounted_servers) == 2
705
+
706
+ def test_infer_fastmcp_server(self, fastmcp_server):
707
+ """FastMCP server instances should infer to FastMCPTransport."""
708
+ transport = infer_transport(fastmcp_server)
709
+ assert isinstance(transport, FastMCPTransport)
710
+
711
+ def test_infer_fastmcp_v1_server(self):
712
+ """FastMCP 1.0 server instances should infer to FastMCPTransport."""
713
+ from mcp.server.fastmcp import FastMCP as FastMCP1
714
+
715
+ server = FastMCP1()
716
+ transport = infer_transport(server)
717
+ assert isinstance(transport, FastMCPTransport)