Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion fastmcp_remote/fastmcp_remote/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,6 @@ async def run(config: RemoteConfig) -> None:
client,
name="fastmcp-remote",
provider_error_strategy="raise",
validate_on_initialize=True,
)
if config.ignore_tools:
server.add_transform(IgnoreTools(config.ignore_tools))
Expand Down
17 changes: 12 additions & 5 deletions fastmcp_slim/fastmcp/server/providers/proxy.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,15 @@ async def on_initialize(
) -> mcp.types.InitializeResult | None:
client = await self.proxy._get_client()
try:
if isinstance(client, StatefulProxyClient):
ctx = context.fastmcp_context
if ctx is not None:
client._proxy_rc_ref[0] = (
ctx.request_context,
ctx._fastmcp,
)
async with client:
pass
await client.initialize()
except McpError:
raise
except (
Expand Down Expand Up @@ -881,7 +888,7 @@ def __init__(
*,
client_factory: ClientFactoryT,
provider_error_strategy: ProviderErrorStrategy = "warn",
validate_on_initialize: bool = False,
forward_initialize: bool = False,
**kwargs,
):
"""Initialize the proxy server.
Expand All @@ -896,16 +903,16 @@ def __init__(
provider_error_strategy: How provider errors should affect aggregate
operations. Defaults to ``"warn"`` for compatibility; use
``"raise"`` when the proxy should surface upstream failures.
validate_on_initialize: If true, connect to the upstream server during
the incoming MCP initialize request.
forward_initialize: Whether incoming initialize requests should
connect to the upstream server before the local proxy responds.
**kwargs: Additional settings for the FastMCP server.
"""
super().__init__(**kwargs)
self.provider_error_strategy = provider_error_strategy
self.client_factory = client_factory
provider: Provider = ProxyProvider(client_factory)
self.add_provider(provider)
if validate_on_initialize:
if forward_initialize:
self.middleware.append(ProxyInitializeMiddleware(self))
self._setup_proxy_ping_handler()

Expand Down
1 change: 1 addition & 0 deletions fastmcp_slim/fastmcp/server/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -2473,6 +2473,7 @@ def create_proxy(
_create_client_factory,
)

settings.setdefault("forward_initialize", True)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Stop forwarding initialize by default in create_proxy

create_proxy() now unconditionally enables forward_initialize, so a proxy handshake always opens and initializes the upstream client before responding locally. This reintroduces the eager remote availability/auth check that this change is trying to remove, and it means default proxies still fail at Client(proxy) time whenever the upstream is down instead of deferring failures to the first proxied operation. That breaks lazy/degraded startup scenarios and keeps the same side effects (extra upstream sessions/auth) on every initialize.

Useful? React with 👍 / 👎.

client_factory = _create_client_factory(target)
return FastMCPProxy(
client_factory=client_factory,
Expand Down
22 changes: 17 additions & 5 deletions tests/server/providers/proxy/test_proxy_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -259,23 +259,35 @@ async def test_proxy_ping_surfaces_wrong_remote_path():
async with run_server_async(remote, transport="http") as url:
proxy = create_proxy(StreamableHttpTransport(url.removesuffix("/mcp")))

async with Client(proxy) as client:
with pytest.raises(McpError, match="Session terminated"):
await client.ping()
with pytest.raises(McpError, match="Session terminated"):
async with Client(proxy):
pass


async def test_proxy_initialize_surfaces_remote_connection_error():
async def test_proxy_initialize_forwards_remote_connection_error():
port = find_available_port()
proxy = create_proxy(
StreamableHttpTransport(f"http://127.0.0.1:{port}/mcp"),
validate_on_initialize=True,
provider_error_strategy="raise",
)

with pytest.raises(McpError, match="Client failed to connect"):
async with Client(proxy):
pass


async def test_proxy_initialize_can_skip_forwarding():
port = find_available_port()
proxy = create_proxy(
StreamableHttpTransport(f"http://127.0.0.1:{port}/mcp"),
forward_initialize=False,
provider_error_strategy="raise",
)

async with Client(proxy):
pass


async def test_proxy_list_tools_surfaces_remote_connection_error():
port = find_available_port()
proxy = create_proxy(
Expand Down
Loading