MCP client session receiver exits on orphaned responses
- Dominant language
- TypeScript
- Stars
- 156k
- Forks
- 24.6k
- Avg merge
- 22h 9m
- Merged PRs (30d)
- 610
Description
## Description
The MCP `BaseSession` routes responses that cannot be matched to an active request through `_handle_incoming(RuntimeError(...))`. `ClientSession` uses the default message handler, which converts incoming exceptions to `ValueError`. That exception escapes `_receive_loop`, terminates the receiver future, and prevents subsequent valid MCP messages from being processed.
This affects two paths:
1. a JSON-RPC response/error whose request ID is no longer present in `_response_streams`;
2. a bare `HTTPStatusError` when there is no waiting response queue.
A late, duplicate, or otherwise orphaned response should be observable, but should not terminate the entire MCP session.
## Steps to reproduce
1. Create a `BaseSession` using a handler with the same exception behavior as `ClientSession._default_message_handler`.
2. Queue a JSON-RPC response for an unknown request ID, followed by a valid notification.
3. Run `_receive_loop()`.
The same result occurs with an unmatched `HTTPStatusError`.
## Actual behavior
Latest `main` raises and exits before processing the notification:
```text
ValueError: Server Error: SessionMessage(... JSONRPCResponse(id=999) ...)
ValueError: Received response with an unknown request ID: Unauthorized
```
The receiver logs `Error in message processing loop` and stops.
## Expected behavior
Log a warning for the orphaned response and continue processing later messages. Transport exceptions that are not orphaned responses should retain their current error behavior.
## Reproduction evidence
A test-only patch against current `main` produces two deterministic failures. A local minimal patch replacing only the two `_handle_incoming(RuntimeError(...))` calls with warning logs passes the complete BaseSession test module (`26 passed`) plus Ruff and `git diff --check`.
I can submit the focused two-file fix and regression tests if maintainers would like to assign this issue.
Contributor guide
Research direction
Start at BaseSession._receive_loop and ClientSession._default_message_handler, then run the BaseSession test module that covers the receive loop. Reproduce both unknown-request responses and unmatched HTTPStatusError cases, and verify orphaned responses are warned about while later valid messages continue processing and other transport exceptions retain their behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- backend-api-design
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 78/100