Skip to content

Python: Define recovery semantics for caller-owned MCP connections #9426

Open

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:

  1. retry the same object;
  2. fail immediately with an actionable ownership error; or
  3. 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/call after a lost response duplicate a server-side side effect?
  • Should Client and ClientSession have identical caller-owned recovery behavior?
  • What does reset=True promise 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 ClientSession behavior.

Related

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    mcpUsage: [Issues, PRs], Target: MCPpythonUsage: [Issues, PRs], Target: Python

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions