Skip to content

fix(transport): accept any 2xx reply for notification-only POSTs - #1424

Open
BlueX888 wants to merge 2 commits into
modelcontextprotocol:mainfrom
BlueX888:fix/accept-2xx-for-notification-posts
Open

BlueX888 wants to merge 2 commits into
modelcontextprotocol:mainfrom
BlueX888:fix/accept-2xx-for-notification-posts

Conversation

@BlueX888

@BlueX888 BlueX888 commented Nov 2, 2026

Copy link
Copy Markdown

Problem

The Streamable HTTP client rejects a 200 OK reply to a notification-only POST (e.g. notifications/initialized) when the reply's Content-Type is absent or non-JSON: a success reply without a body is accepted only for 202/204, Content-Length: 0, application/json or text/event-stream, and anything else falls into UnexpectedContentType. For a notification the reply carries nothing the client needs, so the handshake dies against a server whose only deviation is answering 200 instead of 202 — even though peers like the go-sdk tolerate 200 for non-call POSTs, and this repo already accepts the empty-200 case (#849).

The same fatal fallback exists in the unix-socket transport.

Change

For messages that await no reply (Notification, Response, Error), any 2xx reply is accepted before content-type dispatch — in both the reqwest and unix-socket transports. Requests (ClientRequest) keep the existing strict content-type handling: a reply to a call must still be JSON or SSE. The 202/204/Content-Length: 0/JSON/SSE branches are untouched.

This restarts the work from #1063, which was closed as stale (not rejected). Per the review discussion there, the unix-socket guard now ships with equivalent regression tests.

Tests

  • crates/rmcp/tests/test_streamable_http_empty_2xx_notification.rs: 200 + text/plain, and 200 with no Content-Type (chunked empty body) → Ok(Accepted); both fail before the fix with UnexpectedContentType(…).
  • crates/rmcp/tests/test_unix_socket_transport.rs: the same two cases for UnixSocketHttpClient (compiled on unix; runs on Linux CI).
  • cargo test -p rmcp --lib with the client/transport features: 347 passed; targeted integration tests (4xx error body, client concurrency, initialize error) pass; cargo +nightly fmt --all -- --check and cargo clippy --all-targets --all-features -- -D warnings are clean. The two new unix-socket tests are compile-verified for x86_64-unknown-linux-gnu on this host and run on Linux CI.

A POST carrying only notifications/responses/errors awaits no reply, so
nothing in the response is load-bearing. The client accepted only 202/204,
a literal Content-Length: 0, or JSON/SSE content types; a 200 with
text/plain, or a chunked empty body with no Content-Type, returned
UnexpectedContentType. Against servers that answer
notifications/initialized with 200, that fails the handshake.

Accept any 2xx in the content-type fallback for these messages, in both the
reqwest and unix-socket transports. JSON and SSE replies are still parsed
and streamed as before; requests waiting on a reply keep the strict
content-type check.

Tests: extend test_streamable_http_empty_2xx_notification.rs with the
text/plain and chunked-empty-body shapes plus a request-path guard.
The unix-socket transport got the same "accept any 2xx for a POST that
awaits no response" fallback as the reqwest transport, but its 202-only
test handler never exercised it.

Add two regression tests driving UnixSocketHttpClient::post_message with
notifications/initialized against a socket server that answers 200 with
text/plain, and 200 with no Content-Type/Content-Length (chunked empty
body). Both expect Ok(Accepted). The file is cfg(unix), so these run on
Linux CI and compile out on Windows.
@BlueX888
BlueX888 requested a review from a team as a code owner November 2, 2026 07:30
@github-actions github-actions Bot added T-test Testing related changes T-core Core library changes T-transport Transport layer changes labels Nov 2, 2026
@github-actions
github-actions Bot requested a review from jamadeo November 2, 2026 07:30
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Nov 2, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-11-02T07:32:30.488491Z 8837cfe PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@github-actions

github-actions Bot commented Nov 2, 2026

Copy link
Copy Markdown
Contributor

@jamadeo is on triage rotation this week and is the reviewer for this one.

Labels come from the PR labeler. Please review the change.

Automated triage. Labels are a first pass and the assigned maintainer has the final say.

This branch has not been deployed

No deployments
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-test Testing related changes T-transport Transport layer changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant