Preserve proxy factory errors

🤖 Generated with OpenAI Codex
This commit is contained in:
Jake Kaplan 2026-08-06 10:19:17 -04:00
commit a4afa31004
2 changed files with 34 additions and 5 deletions

View file

@ -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))

View file

@ -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()