mcp: detect dead transports, add Reconnecting state, background reconnect - #15540
Conversation
This was referenced Aug 25, 2026
Contributor
Author
|
Warning This pull request is not mergeable via GitHub because a downstack PR is open. Once all requirements are satisfied, merge this PR as a stack on Graphite.
This stack of pull requests is managed by Graphite. Learn more about stacking. |
This was referenced Aug 25, 2026
mcp: re-mint expired managed proxy tokens on demand instead of failing or misrouting to OAuth
#15538
Draft
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Problem
Nothing observed an MCP server dying: rmcp's cancellation token does not fire on natural death, and
RunningService::waiting()consumes self. Detection was pull-only (Peer::is_transport_closedat the next tool call), so a dead server kept showing Running and advertising stale tools indefinitely. Separately, the built-in Factory MCP recorded its bearer optimistically before the spawn resolved, so a failed builtin spawn was never retried until the token value changed.Changes
TransportLoggingWrapper(which wraps every transport — stdio, streamable HTTP, SSE) flips atokio::sync::watchchannel whenreceive()observes end-of-input or the transport is closed; exposed asTemplatableMCPServerInfo::transport_closed().MCPServerState::Reconnectingand starts a background reconnect. Guards: superseded instances no-op (new per-uuid spawn generation counter, also applied to spawn completion callbacks to prevent stale-state clobbers), explicitly stopped servers are left alone, the circuit breaker surfacesFailedToStartinstead of storming, and servers that would require interactive OAuth (authenticated transport, no cached credentials, no managed refresher) surface a re-auth error rather than popping a login flow. Background healing is deliberately single-attempt per death — tool calls remain the retry driver.MCPServerState::Reconnecting: compile-time-only addition (the enum has no serde anywhere); presented as Starting in the settings card and TUI; non-terminal for the driver's startup wait. Reconnect lookup failures now surface asFailedToStartwith the error message instead of leaving stale state.builtin_server_token, so the next auth event retries even with an unchanged token.SimpleLogger::new_discarding_for_test(behind a newtest-utilfeature) so transport tests don't need a filesystem/executor.Flag-gated by
McpSelfHeal(flag off restores lazy pull-only detection).Tests
Transport-signal tests (end-of-input and explicit close flip the watch), monitor guards (stale generation, stopped server, breaker → FailedToStart, flag-off inert), and the reconnect-lookup-failure surfacing path. Full suites:
cargo test -p mcp(42),-p warp --lib ai::mcp(86), driver (388); clippy clean; TUI feature build checked.