diff --git a/fastmcp_slim/fastmcp/server/providers/proxy.py b/fastmcp_slim/fastmcp/server/providers/proxy.py index 718516867..cf5284a4c 100644 --- a/fastmcp_slim/fastmcp/server/providers/proxy.py +++ b/fastmcp_slim/fastmcp/server/providers/proxy.py @@ -1182,13 +1182,15 @@ class ProxyMetadataMiddleware(Middleware): return _UpstreamServerMetadata.from_discover(result) return _UpstreamServerMetadata.from_client(client) - async def _read_upstream( - self, context: Context | None - ) -> _UpstreamServerMetadata | None: + async def _create_client(self) -> Client: client = self.client_factory() if inspect.isawaitable(client): client = cast(Client, await client) + return client + async def _read_upstream( + self, client: Client, context: Context | None + ) -> _UpstreamServerMetadata | None: if context is not None: _stash_proxy_request_context(client, context) @@ -1229,10 +1231,11 @@ class ProxyMetadataMiddleware(Middleware): mcp_types.InitializeRequest, mcp_types.InitializeResult | None ], ) -> mcp_types.InitializeResult | None: + client = await self._create_client() result = await call_next(context) if result is None: return None - upstream = await self._read_upstream(context.fastmcp_context) + upstream = await self._read_upstream(client, context.fastmcp_context) if upstream is None: return result return result.model_copy(update=self._updates(result, upstream)) @@ -1248,7 +1251,8 @@ class ProxyMetadataMiddleware(Middleware): result = await call_next(context) if not isinstance(result, mcp_types.DiscoverResult): return result - upstream = await self._read_upstream(context.fastmcp_context) + client = await self._create_client() + upstream = await self._read_upstream(client, context.fastmcp_context) if upstream is None: return result return result.model_copy(update=self._updates(result, upstream)) diff --git a/tests/server/providers/proxy/test_server_metadata.py b/tests/server/providers/proxy/test_server_metadata.py index ec5fd9dcf..9aa9b711a 100644 --- a/tests/server/providers/proxy/test_server_metadata.py +++ b/tests/server/providers/proxy/test_server_metadata.py @@ -387,6 +387,31 @@ async def test_client_factory_errors_are_not_swallowed(): pass +@pytest.mark.parametrize("frontend_mode", ["legacy", "auto"]) +@pytest.mark.parametrize("async_factory", [False, True]) +async def test_client_factory_mcp_errors_are_not_swallowed( + frontend_mode: str, async_factory: bool +): + def broken_factory() -> Client: + raise MCPError(code=mcp_types.INTERNAL_ERROR, message="broken client factory") + + async def broken_async_factory() -> Client: + raise MCPError(code=mcp_types.INTERNAL_ERROR, message="broken client factory") + + factory = broken_async_factory if async_factory else broken_factory + provider = ProxyProvider(factory) + gateway = FastMCP( + "gateway", + providers=[provider], + middleware=[ProxyMetadataMiddleware(provider)], + ) + + match = "broken client factory" if frontend_mode == "legacy" else None + with pytest.raises(MCPError, match=match): + async with Client(gateway, mode=frontend_mode): + pass + + @pytest.mark.parametrize("frontend_mode", ["legacy", "auto"]) async def test_unavailable_backend_does_not_block_connection(frontend_mode: str): port = find_available_port()