mirror of
https://github.com/PrefectHQ/fastmcp.git
synced 2026-08-21 04:54:17 +02:00
Remove deprecated client parameter from FastMCPProxy (#2333)
This commit is contained in:
parent
d845d541b8
commit
440ea6130d
3 changed files with 2 additions and 138 deletions
|
|
@ -317,7 +317,6 @@ proxy = FastMCPProxy(client_factory=create_client)
|
|||
|
||||
### Parameters
|
||||
|
||||
- **`client`**: **[DEPRECATED]** A `Client` instance. Use `client_factory` instead for explicit session management.
|
||||
- **`client_factory`**: A callable that returns a `Client` instance when called. This gives you full control over session creation and reuse strategies.
|
||||
|
||||
### Explicit Session Management
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import inspect
|
||||
import warnings
|
||||
from collections.abc import Awaitable, Callable
|
||||
from pathlib import Path
|
||||
from typing import TYPE_CHECKING, Any, cast
|
||||
|
|
@ -20,7 +19,6 @@ from mcp.types import (
|
|||
)
|
||||
from pydantic.networks import AnyUrl
|
||||
|
||||
import fastmcp
|
||||
from fastmcp.client.client import Client, FastMCP1Server
|
||||
from fastmcp.client.elicitation import ElicitResult
|
||||
from fastmcp.client.logging import LogMessage
|
||||
|
|
@ -461,9 +459,8 @@ class FastMCPProxy(FastMCP):
|
|||
|
||||
def __init__(
|
||||
self,
|
||||
client: Client | None = None,
|
||||
*,
|
||||
client_factory: ClientFactoryT | None = None,
|
||||
client_factory: ClientFactoryT,
|
||||
**kwargs,
|
||||
):
|
||||
"""
|
||||
|
|
@ -473,9 +470,6 @@ class FastMCPProxy(FastMCP):
|
|||
Use FastMCP.as_proxy() for convenience with automatic session strategy.
|
||||
|
||||
Args:
|
||||
client: [DEPRECATED] A Client instance. Use client_factory instead for explicit
|
||||
session management. When provided, a client_factory will be automatically
|
||||
created that provides session isolation for backwards compatibility.
|
||||
client_factory: A callable that returns a Client instance when called.
|
||||
This gives you full control over session creation and reuse.
|
||||
Can be either a synchronous or asynchronous function.
|
||||
|
|
@ -484,29 +478,7 @@ class FastMCPProxy(FastMCP):
|
|||
|
||||
super().__init__(**kwargs)
|
||||
|
||||
# Handle client and client_factory parameters
|
||||
if client is not None and client_factory is not None:
|
||||
raise ValueError("Cannot specify both 'client' and 'client_factory'")
|
||||
|
||||
if client is not None:
|
||||
# Deprecated in 2.10.3
|
||||
if fastmcp.settings.deprecation_warnings:
|
||||
warnings.warn(
|
||||
"Passing 'client' to FastMCPProxy is deprecated. Use 'client_factory' instead for explicit session management. "
|
||||
"For automatic session strategy, use FastMCP.as_proxy().",
|
||||
DeprecationWarning,
|
||||
stacklevel=2,
|
||||
)
|
||||
|
||||
# Create a factory that provides session isolation for backwards compatibility
|
||||
def deprecated_client_factory():
|
||||
return client.new()
|
||||
|
||||
self.client_factory = deprecated_client_factory
|
||||
elif client_factory is not None:
|
||||
self.client_factory = client_factory
|
||||
else:
|
||||
raise ValueError("Must specify 'client_factory'")
|
||||
self.client_factory = client_factory
|
||||
|
||||
# Replace the default managers with our specialized proxy managers.
|
||||
self._tool_manager = ProxyToolManager(
|
||||
|
|
|
|||
|
|
@ -1,107 +0,0 @@
|
|||
"""Tests for deprecated FastMCPProxy client parameter."""
|
||||
|
||||
import warnings
|
||||
|
||||
import pytest
|
||||
|
||||
from fastmcp import Client, FastMCP
|
||||
from fastmcp.server.proxy import FastMCPProxy, ProxyClient
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def simple_server():
|
||||
"""Create a simple FastMCP server for testing."""
|
||||
server = FastMCP("TestServer")
|
||||
|
||||
@server.tool
|
||||
def simple_tool() -> str:
|
||||
return "test_result"
|
||||
|
||||
return server
|
||||
|
||||
|
||||
class TestDeprecatedClientParameter:
|
||||
"""Test the deprecated client parameter in FastMCPProxy."""
|
||||
|
||||
def test_client_parameter_deprecation_warning(self, simple_server):
|
||||
"""Test that using the client parameter raises a deprecation warning."""
|
||||
client = Client(simple_server)
|
||||
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
warnings.simplefilter("always") # Ensure all warnings are captured
|
||||
|
||||
FastMCPProxy(client=client)
|
||||
|
||||
# Verify a deprecation warning was raised
|
||||
assert len(w) == 1
|
||||
assert issubclass(w[0].category, DeprecationWarning)
|
||||
assert "client' to FastMCPProxy is deprecated" in str(w[0].message)
|
||||
assert "client_factory" in str(w[0].message)
|
||||
|
||||
def test_client_parameter_still_works(self, simple_server):
|
||||
"""Test that the deprecated client parameter still functions."""
|
||||
client = ProxyClient(simple_server)
|
||||
|
||||
with warnings.catch_warnings():
|
||||
warnings.simplefilter("ignore") # Suppress warnings for functionality test
|
||||
|
||||
proxy = FastMCPProxy(client=client)
|
||||
|
||||
# Verify the proxy was created successfully
|
||||
assert proxy is not None
|
||||
assert hasattr(proxy, "client_factory")
|
||||
assert callable(proxy.client_factory)
|
||||
|
||||
# Verify the factory returns a new client instance (session isolation for backwards compatibility)
|
||||
returned_client = proxy.client_factory()
|
||||
assert returned_client is not client
|
||||
assert isinstance(returned_client, type(client))
|
||||
|
||||
def test_cannot_specify_both_client_and_factory(self, simple_server):
|
||||
"""Test that specifying both client and client_factory raises an error."""
|
||||
client = Client(simple_server)
|
||||
|
||||
def factory():
|
||||
return Client(simple_server)
|
||||
|
||||
with pytest.raises(
|
||||
ValueError, match="Cannot specify both 'client' and 'client_factory'"
|
||||
):
|
||||
FastMCPProxy(client=client, client_factory=factory)
|
||||
|
||||
def test_must_specify_client_factory_when_no_client(self):
|
||||
"""Test that client_factory is required when client is not provided."""
|
||||
with pytest.raises(ValueError, match="Must specify 'client_factory'"):
|
||||
FastMCPProxy()
|
||||
|
||||
def test_client_factory_preferred_over_deprecated_client(self, simple_server):
|
||||
"""Test that the recommended client_factory approach works without warnings."""
|
||||
|
||||
def factory():
|
||||
return ProxyClient(simple_server)
|
||||
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
warnings.simplefilter("always")
|
||||
|
||||
proxy = FastMCPProxy(client_factory=factory)
|
||||
|
||||
# Verify no warnings were raised
|
||||
assert len(w) == 0
|
||||
|
||||
# Verify the proxy works correctly
|
||||
assert proxy is not None
|
||||
assert proxy.client_factory is factory
|
||||
|
||||
async def test_deprecated_client_functional_test(self, simple_server):
|
||||
"""End-to-end test that deprecated client parameter still works functionally."""
|
||||
client = ProxyClient(simple_server)
|
||||
|
||||
with warnings.catch_warnings():
|
||||
warnings.simplefilter("ignore")
|
||||
|
||||
proxy = FastMCPProxy(client=client)
|
||||
|
||||
# Test that the proxy can actually handle requests
|
||||
async with Client(proxy) as proxy_client:
|
||||
result = await proxy_client.call_tool("simple_tool", {})
|
||||
assert result.data == "test_result"
|
||||
Loading…
Add table
Add a link
Reference in a new issue