Repository navigation
Python: Define recovery semantics for caller-owned MCP connections #9426
Description
Problem
Python MCP connection ownership now distinguishes framework-created connections from caller-supplied mcp.Client and ClientSession connections. Cleanup respects that distinction: reset and close may discard and recreate framework-owned connections, while caller-owned objects remain attached.
Recovery does not currently make the same distinction. Tool discovery, prompt discovery, liveness checks, tool calls, and prompt calls all invoke connect(reset=True) or _reconnect_without_loading() after connection loss. For caller-owned connections, reset preserves the same object because Agent Framework cannot recreate something it does not own. The code can therefore log that it is reconnecting and retry against the same ended connection without an explicit recovery contract.
This behavior predates caller-supplied high-level mcp.Client support for the low-level ClientSession path, but adding the third ownership mode makes the ambiguity more visible.
Desired Outcome
Define and document recovery semantics for each ownership mode:
- framework-owned high-level
Client; - caller-owned high-level
Client; - caller-owned low-level
ClientSession.
Decide whether caller-owned connections should:
- retry the same object;
- fail immediately with an actionable ownership error; or
- optionally use a caller-provided connection factory/provider to obtain a replacement.
Centralize the decision so discovery, liveness, tool calls, and prompt calls do not implement subtly different retry policies.
Important Correctness Questions
- Can retrying
tools/callafter a lost response duplicate a server-side side effect? - Should
ClientandClientSessionhave identical caller-owned recovery behavior? - What does
reset=Truepromise when Agent Framework is not allowed to replace the connection? - Which failures mean the connection is unusable versus the individual operation being retryable?
- How should recovery coordinate with the lifecycle-owner task, catalog subscriptions, cancellation, and discovery rollback?
Scope and Non-Goals
This is a lifecycle and ownership policy decision, not a requirement for MCP 2026-07-28 protocol compliance. It should not block the current MCP v2 migration or caller-supplied mcp.Client support.
Subscription-stream recovery while the underlying Client remains usable is a separate boundary tracked by #9109. Agent/workflow ownership of MCP-backed agents is separately tracked by #9369.
Possible Acceptance Criteria
- Recovery behavior is explicitly documented for all three connection ownership modes.
- Framework-owned connections continue to be recreated after recoverable connection loss.
- Caller-owned recovery never claims to have replaced a connection when it reused the same object.
- Tool-call retry behavior accounts for possible duplicate side effects.
- Discovery, liveness, tool, and prompt recovery use one shared ownership-aware policy.
- Tests cover modern and legacy high-level Clients plus caller-owned
ClientSessionbehavior.
Related
- Python: [Feature]: Support the stateless MCP 2026-07-28 revision alongside 2025-era peers #8245 — MCP 2026-07-28 migration umbrella
- Python: Decide recovery policy for ended MCP subscription streams #9109 — ended
subscriptions/listenstream recovery while the Client remains usable - Python: Document MCP v2 client lifecycle and update samples #9237 — MCP v2 client lifecycle ADR and samples
- Python: [Feature]: Python: Define lifecycle ownership for agents with MCP tools inside workflows and orchestrations #9369 — lifecycle ownership for agents with MCP tools inside workflows
Metadata
Metadata
Assignees
Labels
Type
Projects
- StatusShow more project fieldsNo status
Activity