diff --git a/src/mcp/client/streamable_http.py b/src/mcp/client/streamable_http.py index 82de50fd05..dd9515aaf3 100644 --- a/src/mcp/client/streamable_http.py +++ b/src/mcp/client/streamable_http.py @@ -671,7 +671,7 @@ async def terminate_session(self, client: httpx2.AsyncClient) -> None: if response.status_code == 405: logger.debug("Server does not allow session termination") - elif response.status_code not in (200, 204): + elif response.status_code not in (200, 202, 204): logger.warning(f"Session termination failed: {response.status_code}") # pragma: no cover except Exception as exc: # pragma: no cover logger.warning(f"Session termination failed: {exc}") diff --git a/tests/client/test_streamable_http.py b/tests/client/test_streamable_http.py index c6e62ad94a..a779d3411d 100644 --- a/tests/client/test_streamable_http.py +++ b/tests/client/test_streamable_http.py @@ -8,6 +8,7 @@ import base64 import json +import logging from collections.abc import AsyncIterator, Callable, Mapping from typing import Any @@ -968,3 +969,23 @@ async def test_https_endpoint_redirected_to_plain_http_elsewhere_never_suggests_ The server is likely behind a TLS-terminating proxy whose forwarded headers it does not trust, often combined with a trailing-slash difference. Try https://backend.lan:8000/mcp/ instead, or fix the proxy settings.\ """) + + +@pytest.mark.anyio +@pytest.mark.parametrize("status_code", [200, 202, 204]) +async def test_terminate_session_accepts_successful_delete_status_codes( + status_code: int, caplog: pytest.LogCaptureFixture +) -> None: + """HTTP 200, 202 (Accepted), and 204 (No Content) are valid DELETE success statuses (#3546).""" + transport = StreamableHTTPTransport("http://test/mcp") + transport.session_id = "test-session" + + def handler(request: httpx2.Request) -> httpx2.Response: + assert request.method == "DELETE" + return httpx2.Response(status_code) + + async with httpx2.AsyncClient(transport=httpx2.MockTransport(handler)) as http: + with caplog.at_level(logging.WARNING): + await transport.terminate_session(http) + + assert not [rec for rec in caplog.records if "Session termination failed" in rec.message]