Clarify proxy metadata lifecycle

🤖 Generated with OpenAI Codex
This commit is contained in:
Jake Kaplan 2026-08-06 09:58:10 -04:00
commit 8b88d68f4a
2 changed files with 4 additions and 1 deletions

View file

@ -60,7 +60,7 @@ To mount a proxy inside another FastMCP server, see [Mounting External Servers](
## Connection Semantics
FastMCP proxies are lazy bridges. Creating the proxy object and starting the local server do not contact the upstream server. During client negotiation, the proxy makes a best-effort connection to read optional server metadata; an unavailable backend does not prevent the client from connecting to the proxy.
FastMCP proxies are lazy bridges. Creating the proxy object and starting the local server do not contact the upstream server. During client negotiation, the proxy makes a best-effort request for optional server metadata using the backend client's existing lifecycle and negotiation mode; an unavailable backend does not prevent the client from connecting to the proxy.
Subsequent MCP requests such as `ping`, `tools/list`, `resources/list`, `prompts/list`, tool calls, resource reads, sampling, elicitation, logging, and progress connect to the backend as needed. Component provider failures follow `provider_error_strategy`: the default `"warn"` logs and skips a failed provider, while `"raise"` reports the failure to the client.

View file

@ -1167,7 +1167,10 @@ class ProxyMetadataMiddleware(Middleware):
self.identity = identity
async def _read_connected(self, client: Client) -> _UpstreamServerMetadata | None:
"""Read metadata without changing the client's adopted negotiation state."""
if client.mode in MODERN_PROTOCOL_VERSIONS and client.prior_discover is None:
# An exact pin adopts a synthetic result without probing. Read the
# real result directly, but do not adopt it into this borrowed session.
raw = await client.session.send_discover(client.mode)
result_type = raw.get("resultType")
if (