Repoint tests and examples off removed deprecations

Replaces FastMCP.as_proxy() helper calls with create_proxy(), rewrites the
mount() as_proxy=/prefix= kwarg tests to plain mount() (the params are gone),
and deletes deprecation-only tests for as_proxy() and remove_tool().
This commit is contained in:
Jeremiah Lowin 2026-07-06 21:32:54 -04:00
commit 6a6fdcb2bb
No known key found for this signature in database
11 changed files with 39 additions and 176 deletions

View file

@ -3,7 +3,7 @@ This example demonstrates how to set up and use an in-memory FastMCP proxy.
It illustrates the pattern:
1. Create an original FastMCP server with some tools.
2. Create a proxy FastMCP server using ``FastMCP.as_proxy(original_server)``.
2. Create a proxy FastMCP server using ``create_proxy(original_server)``.
3. Use another Client to connect to the proxy server (in-memory) and interact with the original server's tools through the proxy.
"""
@ -13,6 +13,7 @@ from mcp.types import TextContent
from fastmcp import FastMCP
from fastmcp.client import Client
from fastmcp.server import create_proxy
class EchoService:
@ -38,9 +39,9 @@ async def main():
# 2. Proxy Server Creation
print("\nStep 2: Creating the Proxy Server (InMemoryProxy)...")
print(
f" (Using FastMCP.as_proxy to wrap '{original_server.name}' directly)"
f" (Using create_proxy to wrap '{original_server.name}' directly)"
)
proxy_server = FastMCP.as_proxy(original_server, name="InMemoryProxy")
proxy_server = create_proxy(original_server, name="InMemoryProxy")
print(
f" -> Proxy Server '{proxy_server.name}' created, proxying '{original_server.name}'."
)

View file

@ -63,9 +63,9 @@ def check_app_status() -> dict[str, str]:
# Mount sub-applications
app.mount(server=weather_app, prefix="weather")
app.mount(server=weather_app, namespace="weather")
app.mount(server=news_app, prefix="news")
app.mount(server=news_app, namespace="news")
async def get_server_details():

View file

@ -6,6 +6,7 @@ from mcp_types import TextResourceContents
from fastmcp import Client, FastMCP
from fastmcp.client.transports import SSETransport, StreamableHttpTransport
from fastmcp.server import create_proxy
from fastmcp.server.providers.openapi import MCPType, RouteMap
from fastmcp.utilities.tests import run_server_async
@ -63,7 +64,7 @@ async def sse_server():
@pytest.fixture
async def proxy_server(shttp_server: str):
"""Start a proxy server."""
proxy = FastMCP.as_proxy(StreamableHttpTransport(shttp_server))
proxy = create_proxy(StreamableHttpTransport(shttp_server))
async with run_server_async(proxy, transport="http") as url:
yield url

View file

@ -46,10 +46,12 @@ class TestParallelCalls:
return script_file
async def test_parallel_calls(self, stdio_script):
from fastmcp.server import create_proxy
backend_transport = PythonStdioTransport(script_path=stdio_script)
backend_client = Client(transport=backend_transport)
proxy = FastMCP.as_proxy(backend=backend_client, name="PROXY")
proxy = create_proxy(backend_client, name="PROXY")
count = 10

View file

@ -8,6 +8,7 @@ from mcp.server.context import ServerRequestContext
from fastmcp import Client, FastMCP
from fastmcp.exceptions import ToolError
from fastmcp.server import create_proxy
from fastmcp.server.context import Context
from fastmcp.server.middleware import CallNext, Middleware, MiddlewareContext
from fastmcp.tools.base import ToolResult
@ -475,7 +476,7 @@ class TestProxyServer:
):
# proxy server will have its tools listed as well as called in order to
# apply transforms and filters prior to the call.
proxy_server = FastMCP.as_proxy(mcp_server, name="Proxy Server")
proxy_server = create_proxy(mcp_server, name="Proxy Server")
async with Client(proxy_server) as client:
await client.call_tool("add", {"a": 1, "b": 2})
@ -492,7 +493,7 @@ class TestProxyServer:
):
"""Tests that tags on remote FastMCP servers are visible to middleware
via proxy. See https://github.com/PrefectHQ/fastmcp/issues/1300"""
proxy_server = FastMCP.as_proxy(mcp_server, name="Proxy Server")
proxy_server = create_proxy(mcp_server, name="Proxy Server")
TAGS = []

View file

@ -9,6 +9,7 @@ from mcp_types import TextContent
from fastmcp import FastMCP
from fastmcp.client import Client
from fastmcp.client.transports import SSETransport
from fastmcp.server import create_proxy
from fastmcp.tools.base import Tool
from fastmcp.tools.tool_transform import TransformedTool
@ -272,7 +273,7 @@ class TestMultipleServerMount:
)
# Create a proxy server that will fail to connect
unreachable_proxy = FastMCP.as_proxy(
unreachable_proxy = create_proxy(
unreachable_client, name="unreachable_proxy"
)

View file

@ -6,8 +6,8 @@ from contextlib import asynccontextmanager
from fastmcp import FastMCP
from fastmcp.client import Client
from fastmcp.client.transports import FastMCPTransport
from fastmcp.server import create_proxy
from fastmcp.server.providers import FastMCPProvider
from fastmcp.server.providers.proxy import FastMCPProxy
from fastmcp.server.providers.wrapped_provider import _WrappedProvider
from fastmcp.server.transforms import Namespace
@ -25,7 +25,7 @@ class TestProxyServer:
return f"Data for {query}"
# Create proxy server
proxy_server = FastMCP.as_proxy(FastMCPTransport(original_server))
proxy_server = create_proxy(FastMCPTransport(original_server))
# Mount proxy server
main_app = FastMCP("MainApp")
@ -45,7 +45,7 @@ class TestProxyServer:
original_server = FastMCP("OriginalServer")
# Create proxy server
proxy_server = FastMCP.as_proxy(FastMCPTransport(original_server))
proxy_server = create_proxy(FastMCPTransport(original_server))
# Mount proxy server
main_app = FastMCP("MainApp")
@ -74,7 +74,7 @@ class TestProxyServer:
return json.dumps({"api_key": "12345"})
# Create proxy server
proxy_server = FastMCP.as_proxy(FastMCPTransport(original_server))
proxy_server = create_proxy(FastMCPTransport(original_server))
# Mount proxy server
main_app = FastMCP("MainApp")
@ -96,7 +96,7 @@ class TestProxyServer:
return f"Welcome, {name}!"
# Create proxy server
proxy_server = FastMCP.as_proxy(FastMCPTransport(original_server))
proxy_server = create_proxy(FastMCPTransport(original_server))
# Mount proxy server
main_app = FastMCP("MainApp")
@ -108,10 +108,10 @@ class TestProxyServer:
# The message should contain our welcome text
class TestAsProxyKwarg:
"""Test the as_proxy kwarg."""
class TestMountProviderStructure:
"""Test the provider structure produced by mounting."""
async def test_as_proxy_defaults_false(self):
async def test_mount_wraps_in_fastmcp_provider(self):
mcp = FastMCP("Main")
sub = FastMCP("Sub")
@ -133,53 +133,6 @@ class TestAsProxyKwarg:
tools = await mcp.list_tools()
assert {t.name for t in tools} == {"sub_sub_tool"}
async def test_as_proxy_false(self):
mcp = FastMCP("Main")
sub = FastMCP("Sub")
@sub.tool
def sub_tool() -> str:
return "test"
mcp.mount(sub, "sub", as_proxy=False)
# Index 1 because LocalProvider is at index 0
provider = mcp.providers[1]
# Provider is wrapped with Namespace transform
assert isinstance(provider, _WrappedProvider)
assert len(provider._transforms) == 1
assert isinstance(provider._transforms[0], Namespace)
# Inner provider is FastMCPProvider
assert isinstance(provider._inner, FastMCPProvider)
assert provider._inner.server is sub
# Verify namespace is applied
tools = await mcp.list_tools()
assert {t.name for t in tools} == {"sub_sub_tool"}
async def test_as_proxy_true(self):
mcp = FastMCP("Main")
sub = FastMCP("Sub")
@sub.tool
def sub_tool() -> str:
return "test"
mcp.mount(sub, "sub", as_proxy=True)
# Index 1 because LocalProvider is at index 0
provider = mcp.providers[1]
# Provider is wrapped with Namespace transform
assert isinstance(provider, _WrappedProvider)
assert len(provider._transforms) == 1
assert isinstance(provider._transforms[0], Namespace)
# Inner provider is FastMCPProvider wrapping a proxy
assert isinstance(provider._inner, FastMCPProvider)
assert provider._inner.server is not sub
assert isinstance(provider._inner.server, FastMCPProxy)
# Verify namespace is applied
tools = await mcp.list_tools()
assert {t.name for t in tools} == {"sub_sub_tool"}
async def test_lifespan_server_mounted_directly(self):
"""Test that servers with lifespan are mounted directly (not auto-proxied).
@ -214,10 +167,10 @@ class TestAsProxyKwarg:
tools = await mcp.list_tools()
assert {t.name for t in tools} == {"sub_sub_tool"}
async def test_as_proxy_ignored_for_proxy_mounts_default(self):
async def test_mounting_a_proxy_preserves_the_proxy(self):
mcp = FastMCP("Main")
sub = FastMCP("Sub")
sub_proxy = FastMCP.as_proxy(FastMCPTransport(sub))
sub_proxy = create_proxy(FastMCPTransport(sub))
mcp.mount(sub_proxy, "sub")
@ -231,45 +184,11 @@ class TestAsProxyKwarg:
assert isinstance(provider._inner, FastMCPProvider)
assert provider._inner.server is sub_proxy
async def test_as_proxy_ignored_for_proxy_mounts_false(self):
mcp = FastMCP("Main")
sub = FastMCP("Sub")
sub_proxy = FastMCP.as_proxy(FastMCPTransport(sub))
mcp.mount(sub_proxy, "sub", as_proxy=False)
# Index 1 because LocalProvider is at index 0
provider = mcp.providers[1]
# Provider is wrapped with Namespace transform
assert isinstance(provider, _WrappedProvider)
assert len(provider._transforms) == 1
assert isinstance(provider._transforms[0], Namespace)
# Inner provider is FastMCPProvider
assert isinstance(provider._inner, FastMCPProvider)
assert provider._inner.server is sub_proxy
async def test_as_proxy_ignored_for_proxy_mounts_true(self):
mcp = FastMCP("Main")
sub = FastMCP("Sub")
sub_proxy = FastMCP.as_proxy(FastMCPTransport(sub))
mcp.mount(sub_proxy, "sub", as_proxy=True)
# Index 1 because LocalProvider is at index 0
provider = mcp.providers[1]
# Provider is wrapped with Namespace transform
assert isinstance(provider, _WrappedProvider)
assert len(provider._transforms) == 1
assert isinstance(provider._transforms[0], Namespace)
# Inner provider is FastMCPProvider
assert isinstance(provider._inner, FastMCPProvider)
assert provider._inner.server is sub_proxy
async def test_as_proxy_mounts_still_have_live_link(self):
async def test_mounts_have_live_link(self):
mcp = FastMCP("Main")
sub = FastMCP("Sub")
mcp.mount(sub, "sub", as_proxy=True)
mcp.mount(sub, "sub")
assert len(await mcp.list_tools()) == 0
@ -294,7 +213,7 @@ class TestAsProxyKwarg:
def hello():
return "hi"
mcp.mount(sub, as_proxy=True)
mcp.mount(sub)
assert lifespan_check == []

View file

@ -12,6 +12,7 @@ from mcp_types import (
from pydantic import BaseModel, Field
from fastmcp import Client, Context, FastMCP
from fastmcp.server import create_proxy
from fastmcp.client.elicitation import ElicitRequestParams, ElicitResult
from fastmcp.client.logging import LogMessage
from fastmcp.client.sampling import RequestContext, SamplingMessage, SamplingParams
@ -88,7 +89,7 @@ async def proxy_server(fastmcp_server: FastMCP):
"""
A proxy server that forwards interactions with the proxy client to the given fastmcp server.
"""
return FastMCP.as_proxy(ProxyClient(fastmcp_server))
return create_proxy(ProxyClient(fastmcp_server))
class TestProxyClient:
@ -377,7 +378,7 @@ class TestProxyClient:
else:
return f"Elicitation {result.action}"
proxy_server = FastMCP.as_proxy(ProxyClient(fastmcp_server))
proxy_server = create_proxy(ProxyClient(fastmcp_server))
# Test that elicitation works correctly through the proxy
async def elicitation_handler(
@ -407,16 +408,16 @@ class TestProxyClient:
# Create a disconnected client (should use fresh sessions per request)
base_client = Client(fastmcp_server)
# Test both as_proxy convenience method and direct client_factory usage
proxy_via_as_proxy = FastMCP.as_proxy(base_client)
# Test both create_proxy convenience function and direct client_factory usage
proxy_via_create_proxy = create_proxy(base_client)
proxy_via_factory = FastMCPProxy(client_factory=base_client.new)
# Verify the proxies are created successfully - this tests the client factory pattern
assert proxy_via_as_proxy is not None
assert proxy_via_create_proxy is not None
assert proxy_via_factory is not None
# Verify they have the expected client factory behavior
assert hasattr(proxy_via_as_proxy, "_local_provider")
assert hasattr(proxy_via_create_proxy, "_local_provider")
assert hasattr(proxy_via_factory, "_local_provider")
async def test_connected_proxy_client_uses_fresh_sessions(
@ -464,7 +465,7 @@ def roots_backend_server():
@pytest.fixture
async def roots_proxy_server(roots_backend_server: FastMCP):
return FastMCP.as_proxy(ProxyClient(roots_backend_server))
return create_proxy(ProxyClient(roots_backend_server))
class TestProxyServerInitiatedForwardingNonTool:

View file

@ -198,38 +198,6 @@ def test_create_proxy_with_url():
assert client.transport.url == "http://example.com/mcp/"
# --- Deprecated as_proxy tests (verify backwards compatibility) ---
async def test_as_proxy_deprecated_with_server(fastmcp_server):
"""FastMCP.as_proxy should work but emit deprecation warning."""
import warnings
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter("always")
proxy = FastMCP.as_proxy(fastmcp_server)
assert len(w) == 1
assert issubclass(w[0].category, DeprecationWarning)
assert "create_proxy" in str(w[0].message)
async with Client(proxy) as client:
result = await client.call_tool("greet", {"name": "Test"})
assert result.data == "Hello, Test!"
def test_as_proxy_deprecated_with_url():
"""FastMCP.as_proxy should work but emit deprecation warning."""
import warnings
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter("always")
proxy = FastMCP.as_proxy("http://example.com/mcp/")
assert len(w) == 1
assert issubclass(w[0].category, DeprecationWarning)
assert isinstance(proxy, FastMCPProxy)
async def test_proxy_with_async_client_factory():
"""FastMCPProxy should accept an async client_factory."""

View file

@ -1,5 +1,4 @@
import os
import warnings
from pathlib import Path
from tempfile import TemporaryDirectory
from textwrap import dedent
@ -161,37 +160,6 @@ class TestLocalProviderProperty:
assert not any(p.name == "my_prompt" for p in prompts)
class TestRemoveToolDeprecation:
async def test_remove_tool_emits_deprecation_warning(self):
mcp = FastMCP()
@mcp.tool
def my_tool() -> str:
return "result"
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter("always")
mcp.remove_tool("my_tool")
assert len(w) == 1
assert issubclass(w[0].category, DeprecationWarning)
assert "local_provider" in str(w[0].message)
async def test_remove_tool_still_works(self):
mcp = FastMCP()
@mcp.tool
def my_tool() -> str:
return "result"
with warnings.catch_warnings():
warnings.simplefilter("ignore", DeprecationWarning)
mcp.remove_tool("my_tool")
tools = await mcp.list_tools()
assert not any(t.name == "my_tool" for t in tools)
class TestResourcePrefixMounting:
"""Test resource prefixing in mounted servers."""

View file

@ -719,8 +719,9 @@ class TestProxy:
@pytest.fixture
def proxy_server(self, mcp_server: FastMCP) -> FastMCP:
from fastmcp.client.transports import FastMCPTransport
from fastmcp.server import create_proxy
proxy = FastMCP.as_proxy(FastMCPTransport(mcp_server))
proxy = create_proxy(FastMCPTransport(mcp_server))
return proxy
async def test_transform_proxy(self, proxy_server: FastMCP):