Skip to content

fix: isolate streamable HTTP request errors#2607

Open
he-yufeng wants to merge 1 commit into
modelcontextprotocol:mainfrom
he-yufeng:fix/isolate-streamable-http-request-errors
Open

fix: isolate streamable HTTP request errors#2607
he-yufeng wants to merge 1 commit into
modelcontextprotocol:mainfrom
he-yufeng:fix/isolate-streamable-http-request-errors

Conversation

@he-yufeng
Copy link
Copy Markdown

Summary

  • catch per-request failures in the streamable HTTP writer before they escape the shared task group
  • return a JSON-RPC error for the failed request while keeping the writer usable for later requests
  • add a regression test that sends a failing request followed by a successful one on the same transport

Closes #2604

To verify

  • uv run pytest tests/shared/test_streamable_http.py -q -k "request_error_does_not_close_writer"
  • uv run ruff check src/mcp/client/streamable_http.py tests/shared/test_streamable_http.py
  • uv run pyright src/mcp/client/streamable_http.py tests/shared/test_streamable_http.py
  • uv run python -m py_compile src/mcp/client/streamable_http.py tests/shared/test_streamable_http.py
  • git diff --check

@he-yufeng he-yufeng force-pushed the fix/isolate-streamable-http-request-errors branch from b2e8558 to f218dc8 Compare May 15, 2026 16:38
@he-yufeng
Copy link
Copy Markdown
Author

Updated the branch after the CI coverage failure. The missing streamable_http.py exception path is now covered by a notification-error regression test. Local checks: targeted pytest passed; full tests/shared/test_streamable_http.py passed (63 passed); coverage report for src/mcp/client/streamable_http.py no longer lists line 478 as missing; ruff check, ruff format --check, pyright, py_compile, and git diff --check all passed. CI is running again on f218dc8.

@he-yufeng he-yufeng force-pushed the fix/isolate-streamable-http-request-errors branch from f218dc8 to f092047 Compare May 15, 2026 17:29
@he-yufeng
Copy link
Copy Markdown
Author

Updated once more after the Python 3.14 strict coverage run exposed a branch-coverage partial in the new regression test itself. The new test now follows the existing anyio.fail_after pragma style. Local checks: targeted pytest passed; full tests/shared/test_streamable_http.py passed (63 passed); coverage report for tests/shared/test_streamable_http.py is 100.00%; ruff check, ruff format --check, pyright, py_compile, and git diff --check all passed. CI is running again on f092047.

@he-yufeng
Copy link
Copy Markdown
Author

CI is green now on f092047: all matrix test jobs, pre-commit, readme-snippets, conformance, and all-green passed.

@BossChaos

This comment was marked as abuse.

@he-yufeng
Copy link
Copy Markdown
Author

Rebased this onto current upstream/main and resolved the StreamableHTTP in-process transport test refactor conflict.

Kept the request-error isolation behavior and migrated the surrounding tests to the current in-process test setup without bringing back the old socket test style.

Validated locally on Windows:

  • PYTHONUTF8=1 uv run pytest tests/shared/test_streamable_http.py -q -k "request_error_does_not_close_writer or notification_error_still_closes_writer or session_persistence" (3 passed)
  • PYTHONUTF8=1 uv run ruff check src/mcp/client/streamable_http.py tests/shared/test_streamable_http.py
  • PYTHONUTF8=1 uv run ruff format --check src/mcp/client/streamable_http.py tests/shared/test_streamable_http.py
  • PYTHONUTF8=1 uv run pyright src/mcp/client/streamable_http.py tests/shared/test_streamable_http.py
  • PYTHONUTF8=1 uv run python -m py_compile src/mcp/client/streamable_http.py tests/shared/test_streamable_http.py
  • git diff --check upstream/main..HEAD

@he-yufeng he-yufeng force-pushed the fix/isolate-streamable-http-request-errors branch from 004d888 to 94693f1 Compare June 7, 2026 00:33
@he-yufeng
Copy link
Copy Markdown
Author

Follow-up after the matrix failure: the request-error isolation was catching every exception from the request task, which also converted OAuth flow errors into JSON-RPC errors. I narrowed that handler to httpx.HTTPError, so transport/request failures are still isolated for JSON-RPC requests, while auth flow errors keep propagating as OAuthFlowError/OAuthRegistrationError.

Validated locally on Windows:

  • PYTHONUTF8=1 uv run pytest tests/shared/test_streamable_http.py tests/interaction/auth/test_authorize_token.py tests/interaction/auth/test_discovery.py -q -k "request_error_does_not_close_writer or notification_error_still_closes_writer or session_persistence or mismatched_state_on_the_callback or authorize_error_on_the_callback or registration_endpoint or prm_with_a_mismatched_resource" (7 passed)
  • PYTHONUTF8=1 uv run ruff check src/mcp/client/streamable_http.py tests/shared/test_streamable_http.py tests/interaction/auth/test_authorize_token.py tests/interaction/auth/test_discovery.py
  • PYTHONUTF8=1 uv run ruff format --check src/mcp/client/streamable_http.py tests/shared/test_streamable_http.py tests/interaction/auth/test_authorize_token.py tests/interaction/auth/test_discovery.py
  • PYTHONUTF8=1 uv run pyright src/mcp/client/streamable_http.py tests/shared/test_streamable_http.py tests/interaction/auth/test_authorize_token.py tests/interaction/auth/test_discovery.py
  • PYTHONUTF8=1 uv run python -m py_compile src/mcp/client/streamable_http.py tests/shared/test_streamable_http.py tests/interaction/auth/test_authorize_token.py tests/interaction/auth/test_discovery.py
  • git diff --check upstream/main..HEAD

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

streamable_http_client: one concurrent request HTTPStatusError tears down sibling requests

2 participants