Skip to content

fix: conservatively retry legacy server initialization - #1045

Draft
tsarlandie-oai wants to merge 1 commit into
modelcontextprotocol:mainfrom
tsarlandie-oai:codex/rmcp-1040-safe-legacy-lifecycle
Draft

fix: conservatively retry legacy server initialization#1045
tsarlandie-oai wants to merge 1 commit into
modelcontextprotocol:mainfrom
tsarlandie-oai:codex/rmcp-1040-safe-legacy-lifecycle

Conversation

@tsarlandie-oai

@tsarlandie-oai tsarlandie-oai commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Summary

  • make ClientLifecycleMode::Auto own conservative modern-to-legacy lifecycle negotiation
  • recognize correlated METHOD_NOT_FOUND, INVALID_REQUEST, and INVALID_PARAMS responses
  • recognize unsupported-version failures that explicitly reject the attempted modern version, including known initial HTTP 400 responses with id: null and no supported-version list
  • fall back after initial HTTP 404/405 while rejecting 401/403, unrelated IDs, established-session failures, arbitrary messages, and unknown, mixed, or future protocol versions
  • expose typed HTTP status and response body data consistently for reqwest, custom HTTP adapters, and Unix-socket transports
  • keep the HTTP worker available for a real legacy initialize retry without fabricating a JSON-RPC response

Downgrade policy

Auto mode retries legacy initialization only when the discovery probe provides explicit legacy evidence:

  • a correlated -32601, -32600, or -32602 response
  • an explicit rejection of the attempted modern protocol version, with any advertised versions exclusively historical
  • a recognized initial null-ID prevalidation response
  • an initial HTTP 404 or 405

Authentication failures, unrelated response IDs, established-session errors, malformed or arbitrary errors, and unknown/mixed/future version evidence fail without downgrade.

Transport behavior

HttpStatusError carries the original status and body independently of the HTTP backend. Valid JSON-RPC errors in an initial HTTP 400 continue through normal modern-version negotiation; raw prevalidation failures remain typed transport errors that Auto mode can inspect. When a downgrade is safe, Auto sends a real legacy initialize request through the still-live transport worker.

Custom StreamableHttpClient implementations can participate by returning UnexpectedHttpStatus(HttpStatusError) for non-success discovery responses.

Validation

  • full rmcp suite with the documented non-local feature set
  • focused lifecycle, reqwest, custom-adapter, and Unix-socket integration suites
  • draft 2026-07-28 conformance client suite: 376 passed, 0 failed, 0 warnings
  • cargo clippy -p rmcp --all-features --all-targets -- -D warnings
  • minimal client-only non-HTTP build
  • formatting and whitespace checks

This is intended to let Codex remove its complete legacy_discovery_fallback_response workaround while preserving deployed-server interoperability and downgrade safety.

Fixes #1040

@github-actions github-actions Bot added T-test Testing related changes T-core Core library changes T-service Service layer changes T-transport Transport layer changes labels Jul 24, 2026
@tsarlandie-oai
tsarlandie-oai force-pushed the codex/rmcp-1040-safe-legacy-lifecycle branch 2 times, most recently from d28b11d to ed0762c Compare July 27, 2026 22:34
@tsarlandie-oai
tsarlandie-oai force-pushed the codex/rmcp-1040-safe-legacy-lifecycle branch from ed0762c to 8629887 Compare July 27, 2026 22:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

T-core Core library changes T-service Service layer changes T-test Testing related changes T-transport Transport layer changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ClientLifecycleMode::Auto does not fall back for deployed legacy-server responses

1 participant