Jeremiah Lowin commited on
Commit
edc0d82
·
1 Parent(s): 70b186f

Add as_proxy improvements and tests

Browse files
README.md CHANGED
@@ -261,7 +261,7 @@ FastMCP introduces powerful ways to structure and deploy your MCP applications.
261
 
262
  ### Proxy Servers
263
 
264
- Create a FastMCP server that acts as an intermediary for another local or remote MCP server using `FastMCP.from_client()`. This is especially useful for bridging transports (e.g., remote SSE to local Stdio) or adding a layer of logic to a server you don't control.
265
 
266
  Learn more in the [**Proxying Documentation**](https://gofastmcp.com/patterns/proxy).
267
 
 
261
 
262
  ### Proxy Servers
263
 
264
+ Create a FastMCP server that acts as an intermediary for another local or remote MCP server using `FastMCP.as_proxy()`. This is especially useful for bridging transports (e.g., remote SSE to local Stdio) or adding a layer of logic to a server you don't control.
265
 
266
  Learn more in the [**Proxying Documentation**](https://gofastmcp.com/patterns/proxy).
267
 
docs/servers/composition.mdx CHANGED
@@ -167,11 +167,11 @@ FastMCP automatically uses proxy mounting when the mounted server has a custom l
167
 
168
  #### Interaction with Proxy Servers
169
 
170
- When using `FastMCP.from_client()` to create a proxy server, mounting that server will always use proxy mounting:
171
 
172
  ```python
173
  # Create a proxy for a remote server
174
- remote_proxy = FastMCP.from_client(Client("http://example.com/mcp"))
175
 
176
  # Mount the proxy (always uses proxy mounting)
177
  main_server.mount("remote", remote_proxy)
 
167
 
168
  #### Interaction with Proxy Servers
169
 
170
+ When using `FastMCP.as_proxy()` to create a proxy server, mounting that server will always use proxy mounting:
171
 
172
  ```python
173
  # Create a proxy for a remote server
174
+ remote_proxy = FastMCP.as_proxy(Client("http://example.com/mcp"))
175
 
176
  # Mount the proxy (always uses proxy mounting)
177
  main_server.mount("remote", remote_proxy)
docs/servers/fastmcp.mdx CHANGED
@@ -156,7 +156,7 @@ main.mount("sub", sub)
156
 
157
  <VersionBadge version="2.0.0" />
158
 
159
- FastMCP can act as a proxy for any MCP server (local or remote) using `FastMCP.from_client`, letting you bridge transports or add a frontend to existing servers. For example, you can expose a remote SSE server locally via stdio, or vice versa.
160
 
161
  See the [Proxying Servers](/patterns/proxy) guide for details and advanced usage.
162
 
@@ -164,7 +164,7 @@ See the [Proxying Servers](/patterns/proxy) guide for details and advanced usage
164
  from fastmcp import FastMCP, Client
165
 
166
  backend = Client("http://example.com/mcp/sse")
167
- proxy = FastMCP.from_client(backend, name="ProxyServer")
168
  # Now use the proxy like any FastMCP server
169
  ```
170
 
 
156
 
157
  <VersionBadge version="2.0.0" />
158
 
159
+ FastMCP can act as a proxy for any MCP server (local or remote) using `FastMCP.as_proxy`, letting you bridge transports or add a frontend to existing servers. For example, you can expose a remote SSE server locally via stdio, or vice versa.
160
 
161
  See the [Proxying Servers](/patterns/proxy) guide for details and advanced usage.
162
 
 
164
  from fastmcp import FastMCP, Client
165
 
166
  backend = Client("http://example.com/mcp/sse")
167
+ proxy = FastMCP.as_proxy(backend, name="ProxyServer")
168
  # Now use the proxy like any FastMCP server
169
  ```
170
 
docs/servers/proxy.mdx CHANGED
@@ -8,7 +8,9 @@ import { VersionBadge } from '/snippets/version-badge.mdx'
8
 
9
  <VersionBadge version="2.0.0" />
10
 
11
- FastMCP provides a powerful proxying capability that allows one FastMCP server instance to act as a frontend for another MCP server (which could be remote, running on a different transport, or even another FastMCP instance). This is achieved using the `FastMCP.from_client()` class method.
 
 
12
 
13
  ## What is Proxying?
14
 
@@ -37,26 +39,23 @@ sequenceDiagram
37
 
38
  ## Creating a Proxy
39
 
40
- The easiest way to create a proxy is using the `FastMCP.from_client()` class method. This creates a standard FastMCP server that forwards requests to another MCP server.
41
 
42
  ```python
43
- from fastmcp import FastMCP, Client
44
-
45
- # Create a client configured to talk to the backend server
46
- # This could be any MCP server - remote, local, or using any transport
47
- backend_client = Client("backend_server.py") # Could be "http://remote.server/sse", etc.
48
 
49
- # Create the proxy server with from_client()
50
- proxy_server = FastMCP.from_client(
51
- backend_client,
52
  name="MyProxyServer" # Optional settings for the proxy
53
  )
54
 
55
- # That's it! You now have a proxy FastMCP server that can be used
56
- # with any transport (SSE, stdio, etc.) just like any other FastMCP server
 
57
  ```
58
 
59
- **How `from_client` Works:**
60
 
61
  1. It connects to the backend server using the provided client.
62
  2. It discovers all the tools, resources, resource templates, and prompts available on the backend server.
@@ -72,13 +71,10 @@ Currently, proxying focuses primarily on exposing the major MCP objects (tools,
72
  A common use case is to bridge transports. For example, making a remote SSE server available locally via Stdio:
73
 
74
  ```python
75
- from fastmcp import FastMCP, Client
76
 
77
- # Client targeting a remote SSE server
78
- client = Client("http://example.com/mcp/sse")
79
-
80
- # Create a proxy server - it's just a regular FastMCP server
81
- proxy = FastMCP.from_client(client, name="SSE to Stdio Proxy")
82
 
83
  # The proxy can now be used with any transport
84
  # No special handling needed - it works like any FastMCP server
@@ -89,7 +85,7 @@ proxy = FastMCP.from_client(client, name="SSE to Stdio Proxy")
89
  You can also proxy an in-memory `FastMCP` instance, which is useful for adjusting the configuration or behavior of a server you don't completely control.
90
 
91
  ```python
92
- from fastmcp import FastMCP, Client
93
 
94
  # Original server
95
  original_server = FastMCP(name="Original")
@@ -98,12 +94,9 @@ original_server = FastMCP(name="Original")
98
  def tool_a() -> str:
99
  return "A"
100
 
101
- # To proxy an in-memory server, first create a Client to it.
102
- client_to_original = Client(original_server)
103
-
104
- # Create a proxy of the original server using the client.
105
- proxy = FastMCP.from_client(
106
- client_to_original,
107
  name="Proxy Server"
108
  )
109
 
@@ -113,6 +106,6 @@ proxy = FastMCP.from_client(
113
 
114
  ## `FastMCPProxy` Class
115
 
116
- Internally, `FastMCP.from_client()` uses the `FastMCPProxy` class. You generally don't need to interact with this class directly, but it's available if needed.
117
 
118
  Using the class directly might be necessary for advanced scenarios, like subclassing `FastMCPProxy` to add custom logic before or after forwarding requests.
 
8
 
9
  <VersionBadge version="2.0.0" />
10
 
11
+ FastMCP provides a powerful proxying capability that allows one FastMCP server instance to act as a frontend for another MCP server (which could be remote, running on a different transport, or even another FastMCP instance). This is achieved using the `FastMCP.as_proxy()` class method.
12
+
13
+ `as_proxy()` accepts either an existing `Client` or any argument that can be passed to a `Client` as its `transport` parameter&mdash;such as another `FastMCP` instance or a URL to a remote server.
14
 
15
  ## What is Proxying?
16
 
 
39
 
40
  ## Creating a Proxy
41
 
42
+ The easiest way to create a proxy is using the `FastMCP.as_proxy()` class method. This creates a standard FastMCP server that forwards requests to another MCP server.
43
 
44
  ```python
45
+ from fastmcp import FastMCP
 
 
 
 
46
 
47
+ # Provide the backend in any form accepted by Client
48
+ proxy_server = FastMCP.as_proxy(
49
+ "backend_server.py", # Could also be a FastMCP instance or a remote URL
50
  name="MyProxyServer" # Optional settings for the proxy
51
  )
52
 
53
+ # Or create the Client yourself for custom configuration
54
+ backend_client = Client("backend_server.py")
55
+ proxy_from_client = FastMCP.as_proxy(backend_client)
56
  ```
57
 
58
+ **How `as_proxy` Works:**
59
 
60
  1. It connects to the backend server using the provided client.
61
  2. It discovers all the tools, resources, resource templates, and prompts available on the backend server.
 
71
  A common use case is to bridge transports. For example, making a remote SSE server available locally via Stdio:
72
 
73
  ```python
74
+ from fastmcp import FastMCP
75
 
76
+ # Target a remote SSE server directly by URL
77
+ proxy = FastMCP.as_proxy("http://example.com/mcp/sse", name="SSE to Stdio Proxy")
 
 
 
78
 
79
  # The proxy can now be used with any transport
80
  # No special handling needed - it works like any FastMCP server
 
85
  You can also proxy an in-memory `FastMCP` instance, which is useful for adjusting the configuration or behavior of a server you don't completely control.
86
 
87
  ```python
88
+ from fastmcp import FastMCP
89
 
90
  # Original server
91
  original_server = FastMCP(name="Original")
 
94
  def tool_a() -> str:
95
  return "A"
96
 
97
+ # Create a proxy of the original server directly
98
+ proxy = FastMCP.as_proxy(
99
+ original_server,
 
 
 
100
  name="Proxy Server"
101
  )
102
 
 
106
 
107
  ## `FastMCPProxy` Class
108
 
109
+ Internally, `FastMCP.as_proxy()` uses the `FastMCPProxy` class. You generally don't need to interact with this class directly, but it's available if needed.
110
 
111
  Using the class directly might be necessary for advanced scenarios, like subclassing `FastMCPProxy` to add custom logic before or after forwarding requests.
examples/in_memory_proxy_example.py CHANGED
@@ -3,9 +3,8 @@ This example demonstrates how to set up and use an in-memory FastMCP proxy.
3
 
4
  It illustrates the pattern:
5
  1. Create an original FastMCP server with some tools.
6
- 2. Create a Client that connects to this original server (in-memory).
7
- 3. Create a proxy FastMCP server using FastMCP.from_client(), passing it the client from step 2.
8
- 4. Use another Client to connect to the proxy server (in-memory) and interact with the original server's tools through the proxy.
9
  """
10
 
11
  import asyncio
@@ -36,24 +35,18 @@ async def main():
36
  original_server.add_tool(EchoService().echo)
37
  print(f" -> Original Server '{original_server.name}' created.")
38
 
39
- # 2. Client for Proxy
40
- print("\nStep 2: Creating a Client to connect to the Original Server...")
41
- print(" (This client will be used internally by the proxy server)")
42
- client_to_original = Client(original_server)
43
- print(f" -> Client for proxy created, targeting '{original_server.name}'.")
44
-
45
- # 3. Proxy Server Creation
46
- print("\nStep 3: Creating the Proxy Server (InMemoryProxy)...")
47
  print(
48
- f" (Using FastMCP.from_client, passing it the client from Step 2 that targets '{original_server.name}')"
49
  )
50
- proxy_server = FastMCP.from_client(client_to_original, name="InMemoryProxy")
51
  print(
52
  f" -> Proxy Server '{proxy_server.name}' created, proxying '{original_server.name}'."
53
  )
54
 
55
- # 4. Interacting via Proxy
56
- print("\nStep 4: Using a new Client to connect to the Proxy Server and interact...")
57
  async with Client(proxy_server) as final_client:
58
  print(f" -> Successfully connected to proxy '{proxy_server.name}'.")
59
 
 
3
 
4
  It illustrates the pattern:
5
  1. Create an original FastMCP server with some tools.
6
+ 2. Create a proxy FastMCP server using ``FastMCP.as_proxy(original_server)``.
7
+ 3. Use another Client to connect to the proxy server (in-memory) and interact with the original server's tools through the proxy.
 
8
  """
9
 
10
  import asyncio
 
35
  original_server.add_tool(EchoService().echo)
36
  print(f" -> Original Server '{original_server.name}' created.")
37
 
38
+ # 2. Proxy Server Creation
39
+ print("\nStep 2: Creating the Proxy Server (InMemoryProxy)...")
 
 
 
 
 
 
40
  print(
41
+ f" (Using FastMCP.as_proxy to wrap '{original_server.name}' directly)"
42
  )
43
+ proxy_server = FastMCP.as_proxy(original_server, name="InMemoryProxy")
44
  print(
45
  f" -> Proxy Server '{proxy_server.name}' created, proxying '{original_server.name}'."
46
  )
47
 
48
+ # 3. Interacting via Proxy
49
+ print("\nStep 3: Using a new Client to connect to the Proxy Server and interact...")
50
  async with Client(proxy_server) as final_client:
51
  print(f" -> Successfully connected to proxy '{proxy_server.name}'.")
52
 
src/fastmcp/server/server.py CHANGED
@@ -11,6 +11,7 @@ from contextlib import (
11
  asynccontextmanager,
12
  )
13
  from functools import partial
 
14
  from typing import TYPE_CHECKING, Any, Generic, Literal
15
 
16
  import anyio
@@ -60,6 +61,7 @@ from fastmcp.utilities.logging import get_logger
60
 
61
  if TYPE_CHECKING:
62
  from fastmcp.client import Client
 
63
  from fastmcp.server.openapi import FastMCPOpenAPI
64
  from fastmcp.server.proxy import FastMCPProxy
65
  logger = get_logger(__name__)
@@ -1104,14 +1106,47 @@ class FastMCP(Generic[LifespanResultT]):
1104
  openapi_spec=app.openapi(), client=client, name=name, **settings
1105
  )
1106
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1107
  @classmethod
1108
  def from_client(cls, client: Client, **settings: Any) -> FastMCPProxy:
1109
  """
1110
  Create a FastMCP proxy server from a FastMCP client.
1111
  """
1112
- from fastmcp.server.proxy import FastMCPProxy
 
 
 
 
 
1113
 
1114
- return FastMCPProxy(client=client, **settings)
1115
 
1116
 
1117
  def _validate_resource_prefix(prefix: str) -> None:
 
11
  asynccontextmanager,
12
  )
13
  from functools import partial
14
+ from pathlib import Path
15
  from typing import TYPE_CHECKING, Any, Generic, Literal
16
 
17
  import anyio
 
61
 
62
  if TYPE_CHECKING:
63
  from fastmcp.client import Client
64
+ from fastmcp.client.transports import ClientTransport
65
  from fastmcp.server.openapi import FastMCPOpenAPI
66
  from fastmcp.server.proxy import FastMCPProxy
67
  logger = get_logger(__name__)
 
1106
  openapi_spec=app.openapi(), client=client, name=name, **settings
1107
  )
1108
 
1109
+ @classmethod
1110
+ def as_proxy(
1111
+ cls,
1112
+ backend: Client
1113
+ | ClientTransport
1114
+ | FastMCP[Any]
1115
+ | AnyUrl
1116
+ | Path
1117
+ | dict[str, Any]
1118
+ | str,
1119
+ **settings: Any,
1120
+ ) -> FastMCPProxy:
1121
+ """Create a FastMCP proxy server for the given backend.
1122
+
1123
+ The ``backend`` argument can be either an existing :class:`~fastmcp.client.Client`
1124
+ instance or any value accepted as the ``transport`` argument of
1125
+ :class:`~fastmcp.client.Client`. This mirrors the convenience of the
1126
+ ``Client`` constructor.
1127
+ """
1128
+ from fastmcp.server.proxy import FastMCPProxy
1129
+
1130
+ if isinstance(backend, Client):
1131
+ client = backend
1132
+ else:
1133
+ client = Client(backend)
1134
+
1135
+ return FastMCPProxy(client=client, **settings)
1136
+
1137
  @classmethod
1138
  def from_client(cls, client: Client, **settings: Any) -> FastMCPProxy:
1139
  """
1140
  Create a FastMCP proxy server from a FastMCP client.
1141
  """
1142
+ # Deprecated since 2.4.0
1143
+ warnings.warn(
1144
+ "FastMCP.from_client() is deprecated; use FastMCP.as_proxy() instead.",
1145
+ DeprecationWarning,
1146
+ stacklevel=2,
1147
+ )
1148
 
1149
+ return cls.as_proxy(client, **settings)
1150
 
1151
 
1152
  def _validate_resource_prefix(prefix: str) -> None:
tests/server/test_import_server.py CHANGED
@@ -299,7 +299,7 @@ async def test_import_with_proxy_tools():
299
  def get_data(query: str) -> str:
300
  return f"Data for query: {query}"
301
 
302
- proxy_app = FastMCP.from_client(Client(api_app))
303
  await main_app.import_server("api", proxy_app)
304
 
305
  result = await main_app._mcp_call_tool("api_get_data", {"query": "test"})
@@ -323,7 +323,7 @@ async def test_import_with_proxy_prompts():
323
  """Example greeting prompt."""
324
  return f"Hello, {name} from API!"
325
 
326
- proxy_app = FastMCP.from_client(Client(api_app))
327
  await main_app.import_server("api", proxy_app)
328
 
329
  result = await main_app._mcp_get_prompt("api_greeting", {"name": "World"})
@@ -351,7 +351,7 @@ async def test_import_with_proxy_resources():
351
  "base_url": "https://api.example.com",
352
  }
353
 
354
- proxy_app = FastMCP.from_client(Client(api_app))
355
  await main_app.import_server("api", proxy_app)
356
 
357
  # Access the resource through the main app with the prefixed key
@@ -379,7 +379,7 @@ async def test_import_with_proxy_resource_templates():
379
  def create_user(name: str, email: str):
380
  return {"name": name, "email": email}
381
 
382
- proxy_app = FastMCP.from_client(Client(api_app))
383
  await main_app.import_server("api", proxy_app)
384
 
385
  # Instantiate the template through the main app with the prefixed key
 
299
  def get_data(query: str) -> str:
300
  return f"Data for query: {query}"
301
 
302
+ proxy_app = FastMCP.as_proxy(Client(api_app))
303
  await main_app.import_server("api", proxy_app)
304
 
305
  result = await main_app._mcp_call_tool("api_get_data", {"query": "test"})
 
323
  """Example greeting prompt."""
324
  return f"Hello, {name} from API!"
325
 
326
+ proxy_app = FastMCP.as_proxy(Client(api_app))
327
  await main_app.import_server("api", proxy_app)
328
 
329
  result = await main_app._mcp_get_prompt("api_greeting", {"name": "World"})
 
351
  "base_url": "https://api.example.com",
352
  }
353
 
354
+ proxy_app = FastMCP.as_proxy(Client(api_app))
355
  await main_app.import_server("api", proxy_app)
356
 
357
  # Access the resource through the main app with the prefixed key
 
379
  def create_user(name: str, email: str):
380
  return {"name": name, "email": email}
381
 
382
+ proxy_app = FastMCP.as_proxy(Client(api_app))
383
  await main_app.import_server("api", proxy_app)
384
 
385
  # Instantiate the template through the main app with the prefixed key
tests/server/test_mount.py CHANGED
@@ -373,7 +373,7 @@ class TestProxyServer:
373
  return f"Data for {query}"
374
 
375
  # Create proxy server
376
- proxy_server = FastMCP.from_client(
377
  Client(transport=FastMCPTransport(original_server))
378
  )
379
 
@@ -396,7 +396,7 @@ class TestProxyServer:
396
  original_server = FastMCP("OriginalServer")
397
 
398
  # Create proxy server
399
- proxy_server = FastMCP.from_client(
400
  Client(transport=FastMCPTransport(original_server))
401
  )
402
 
@@ -428,7 +428,7 @@ class TestProxyServer:
428
  return {"api_key": "12345"}
429
 
430
  # Create proxy server
431
- proxy_server = FastMCP.from_client(
432
  Client(transport=FastMCPTransport(original_server))
433
  )
434
 
@@ -452,7 +452,7 @@ class TestProxyServer:
452
  return f"Welcome, {name}!"
453
 
454
  # Create proxy server
455
- proxy_server = FastMCP.from_client(
456
  Client(transport=FastMCPTransport(original_server))
457
  )
458
 
@@ -510,7 +510,7 @@ class TestAsProxyKwarg:
510
  async def test_as_proxy_ignored_for_proxy_mounts_default(self):
511
  mcp = FastMCP("Main")
512
  sub = FastMCP("Sub")
513
- sub_proxy = FastMCP.from_client(Client(transport=FastMCPTransport(sub)))
514
 
515
  mcp.mount("sub", sub_proxy)
516
 
@@ -519,7 +519,7 @@ class TestAsProxyKwarg:
519
  async def test_as_proxy_ignored_for_proxy_mounts_false(self):
520
  mcp = FastMCP("Main")
521
  sub = FastMCP("Sub")
522
- sub_proxy = FastMCP.from_client(Client(transport=FastMCPTransport(sub)))
523
 
524
  mcp.mount("sub", sub_proxy, as_proxy=False)
525
 
@@ -528,7 +528,7 @@ class TestAsProxyKwarg:
528
  async def test_as_proxy_ignored_for_proxy_mounts_true(self):
529
  mcp = FastMCP("Main")
530
  sub = FastMCP("Sub")
531
- sub_proxy = FastMCP.from_client(Client(transport=FastMCPTransport(sub)))
532
 
533
  mcp.mount("sub", sub_proxy, as_proxy=True)
534
 
 
373
  return f"Data for {query}"
374
 
375
  # Create proxy server
376
+ proxy_server = FastMCP.as_proxy(
377
  Client(transport=FastMCPTransport(original_server))
378
  )
379
 
 
396
  original_server = FastMCP("OriginalServer")
397
 
398
  # Create proxy server
399
+ proxy_server = FastMCP.as_proxy(
400
  Client(transport=FastMCPTransport(original_server))
401
  )
402
 
 
428
  return {"api_key": "12345"}
429
 
430
  # Create proxy server
431
+ proxy_server = FastMCP.as_proxy(
432
  Client(transport=FastMCPTransport(original_server))
433
  )
434
 
 
452
  return f"Welcome, {name}!"
453
 
454
  # Create proxy server
455
+ proxy_server = FastMCP.as_proxy(
456
  Client(transport=FastMCPTransport(original_server))
457
  )
458
 
 
510
  async def test_as_proxy_ignored_for_proxy_mounts_default(self):
511
  mcp = FastMCP("Main")
512
  sub = FastMCP("Sub")
513
+ sub_proxy = FastMCP.as_proxy(Client(transport=FastMCPTransport(sub)))
514
 
515
  mcp.mount("sub", sub_proxy)
516
 
 
519
  async def test_as_proxy_ignored_for_proxy_mounts_false(self):
520
  mcp = FastMCP("Main")
521
  sub = FastMCP("Sub")
522
+ sub_proxy = FastMCP.as_proxy(Client(transport=FastMCPTransport(sub)))
523
 
524
  mcp.mount("sub", sub_proxy, as_proxy=False)
525
 
 
528
  async def test_as_proxy_ignored_for_proxy_mounts_true(self):
529
  mcp = FastMCP("Main")
530
  sub = FastMCP("Sub")
531
+ sub_proxy = FastMCP.as_proxy(Client(transport=FastMCPTransport(sub)))
532
 
533
  mcp.mount("sub", sub_proxy, as_proxy=True)
534
 
tests/server/test_proxy.py CHANGED
@@ -66,7 +66,7 @@ def fastmcp_server():
66
  @pytest.fixture
67
  async def proxy_server(fastmcp_server):
68
  """Fixture that creates a FastMCP proxy server."""
69
- return FastMCP.from_client(Client(transport=FastMCPTransport(fastmcp_server)))
70
 
71
 
72
  async def test_create_proxy(fastmcp_server):
@@ -81,6 +81,29 @@ async def test_create_proxy(fastmcp_server):
81
  assert server.name == "FastMCP"
82
 
83
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
84
  class TestTools:
85
  async def test_get_tools(self, proxy_server):
86
  tools = await proxy_server.get_tools()
 
66
  @pytest.fixture
67
  async def proxy_server(fastmcp_server):
68
  """Fixture that creates a FastMCP proxy server."""
69
+ return FastMCP.as_proxy(Client(transport=FastMCPTransport(fastmcp_server)))
70
 
71
 
72
  async def test_create_proxy(fastmcp_server):
 
81
  assert server.name == "FastMCP"
82
 
83
 
84
+ async def test_as_proxy_with_server(fastmcp_server):
85
+ """FastMCP.as_proxy should accept a FastMCP instance."""
86
+ proxy = FastMCP.as_proxy(fastmcp_server)
87
+ result = await proxy._mcp_call_tool("greet", {"name": "Test"})
88
+ assert isinstance(result[0], mcp.types.TextContent)
89
+ assert result[0].text == "Hello, Test!"
90
+
91
+
92
+ async def test_as_proxy_with_transport(fastmcp_server):
93
+ """FastMCP.as_proxy should accept a ClientTransport."""
94
+ proxy = FastMCP.as_proxy(FastMCPTransport(fastmcp_server))
95
+ result = await proxy._mcp_call_tool("greet", {"name": "Test"})
96
+ assert isinstance(result[0], mcp.types.TextContent)
97
+ assert result[0].text == "Hello, Test!"
98
+
99
+
100
+ def test_as_proxy_with_url():
101
+ """FastMCP.as_proxy should accept a URL without connecting."""
102
+ proxy = FastMCP.as_proxy("http://example.com/mcp")
103
+ assert isinstance(proxy, FastMCPProxy)
104
+ assert repr(proxy.client.transport).startswith("<StreamableHttp(")
105
+
106
+
107
  class TestTools:
108
  async def test_get_tools(self, proxy_server):
109
  tools = await proxy_server.get_tools()
tests/test_deprecated.py CHANGED
@@ -6,7 +6,7 @@ from unittest.mock import AsyncMock, patch
6
  import pytest
7
  from starlette.applications import Starlette
8
 
9
- from fastmcp import FastMCP
10
 
11
 
12
  def test_fastmcp_kwargs_settings_deprecation_warning():
@@ -91,3 +91,10 @@ def test_http_app_with_sse_transport():
91
  w for w in recorded_warnings if issubclass(w.category, DeprecationWarning)
92
  ]
93
  assert len(deprecation_warnings) == 0
 
 
 
 
 
 
 
 
6
  import pytest
7
  from starlette.applications import Starlette
8
 
9
+ from fastmcp import Client, FastMCP
10
 
11
 
12
  def test_fastmcp_kwargs_settings_deprecation_warning():
 
91
  w for w in recorded_warnings if issubclass(w.category, DeprecationWarning)
92
  ]
93
  assert len(deprecation_warnings) == 0
94
+
95
+
96
+ def test_from_client_deprecation_warning():
97
+ """Test that FastMCP.from_client raises a deprecation warning."""
98
+ server = FastMCP("TestServer")
99
+ with pytest.warns(DeprecationWarning, match="from_client"):
100
+ FastMCP.from_client(Client(server))