Jeremiah Lowin commited on
Commit
f0173da
·
unverified ·
2 Parent(s): f8721ad407f55e

Merge pull request #539 from jlowin/codex/add-support-for-fastmcp-1.0-server

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
 
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(
@@ -558,6 +565,7 @@ class MCPConfigTransport(ClientTransport):
558
  def infer_transport(
559
  transport: ClientTransport
560
  | FastMCPServer
 
561
  | AnyUrl
562
  | Path
563
  | MCPConfig
@@ -573,7 +581,7 @@ def infer_transport(
573
 
574
  The function supports these input types:
575
  - ClientTransport: Used directly without modification
576
- - FastMCPServer: Creates an in-memory FastMCPTransport
577
  - Path or str (file path): Creates PythonStdioTransport (.py) or NodeStdioTransport (.js)
578
  - AnyUrl or str (URL): Creates StreamableHttpTransport (default) or SSETransport (for /sse endpoints)
579
  - MCPConfig or dict: Creates MCPConfigTransport, potentially connecting to multiple servers
@@ -610,8 +618,8 @@ def infer_transport(
610
  if isinstance(transport, ClientTransport):
611
  return transport
612
 
613
- # the transport is a FastMCP server
614
- elif isinstance(transport, FastMCPServer):
615
  inferred_transport = FastMCPTransport(mcp=transport)
616
 
617
  # 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(
 
565
  def infer_transport(
566
  transport: ClientTransport
567
  | FastMCPServer
568
+ | FastMCP1Server
569
  | AnyUrl
570
  | Path
571
  | MCPConfig
 
581
 
582
  The function supports these input types:
583
  - ClientTransport: Used directly without modification
584
+ - FastMCPServer or FastMCP1Server: Creates an in-memory FastMCPTransport
585
  - Path or str (file path): Creates PythonStdioTransport (.py) or NodeStdioTransport (.js)
586
  - AnyUrl or str (URL): Creates StreamableHttpTransport (default) or SSETransport (for /sse endpoints)
587
  - MCPConfig or dict: Creates MCPConfigTransport, potentially connecting to multiple servers
 
618
  if isinstance(transport, ClientTransport):
619
  return transport
620
 
621
+ # the transport is a FastMCP server (2.x or 1.0)
622
+ elif isinstance(transport, FastMCPServer | FastMCP1Server):
623
  inferred_transport = FastMCPTransport(mcp=transport)
624
 
625
  # the transport is a path to a script
tests/client/test_client.py CHANGED
@@ -673,7 +673,7 @@ class TestInferTransport:
673
  assert transport.transport.command == "echo"
674
  assert transport.transport.args == ["hello"]
675
 
676
- def test_infer_composite_client(config):
677
  config = {
678
  "mcpServers": {
679
  "local": {
@@ -689,4 +689,17 @@ class TestInferTransport:
689
  transport = infer_transport(config)
690
  assert isinstance(transport, MCPConfigTransport)
691
  assert isinstance(transport.transport, FastMCPTransport)
692
- assert len(transport.transport.server._mounted_servers) == 2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
673
  assert transport.transport.command == "echo"
674
  assert transport.transport.args == ["hello"]
675
 
676
+ def test_infer_composite_client(self):
677
  config = {
678
  "mcpServers": {
679
  "local": {
 
689
  transport = infer_transport(config)
690
  assert isinstance(transport, MCPConfigTransport)
691
  assert isinstance(transport.transport, FastMCPTransport)
692
+ assert len(cast(FastMCP, transport.transport.server)._mounted_servers) == 2
693
+
694
+ def test_infer_fastmcp_server(self, fastmcp_server):
695
+ """FastMCP server instances should infer to FastMCPTransport."""
696
+ transport = infer_transport(fastmcp_server)
697
+ assert isinstance(transport, FastMCPTransport)
698
+
699
+ def test_infer_fastmcp_v1_server(self):
700
+ """FastMCP 1.0 server instances should infer to FastMCPTransport."""
701
+ from mcp.server.fastmcp import FastMCP as FastMCP1
702
+
703
+ server = FastMCP1()
704
+ transport = infer_transport(server)
705
+ assert isinstance(transport, FastMCPTransport)