Streamable HTTP server: Accept and Content-Type are matched case-sensitively and by substring/prefix

Geschlossen
#1,381 1 Kommentar 0 Reaktionen 1 zugewiesene Person Auf GitHub ansehen

Maintainer antworten meist innerhalb von 3 Tagen

@DaleSeo arbeitet bereits daran.

Seit 20.10.2026.

  • #1382 von @passionworkeer — offen

Bewertung

Dieses Issue wurde noch nicht bewertet.

Beschreibung

bug P1 ready for work T-transport

Version: rmcp 3.6.0 (also 3.5.1), transport-streamable-http-server, StreamableHttpService.

What happens

The POST and GET handlers in crates/rmcp/src/transport/streamable_http_server/tower.rs check Accept and Content-Type with raw string matching:

// POST, Accept
header.contains(JSON_MIME_TYPE) && header.contains(EVENT_STREAM_MIME_TYPE)
// POST, Content-Type
header.starts_with(JSON_MIME_TYPE)
// GET, Accept
header.contains(EVENT_STREAM_MIME_TYPE)

That gives these results:

Request Result Expected
Content-Type: Application/JSON 415 accepted
Accept: APPLICATION/JSON, TEXT/EVENT-STREAM 406 accepted
Content-Type: application/jsonx accepted 415
Accept: application/json-seq, text/event-stream accepted 406
Accept: application/json;q=0, text/event-stream accepted 406 (q=0 means "not acceptable")
Accept split across two header lines (application/json and text/event-stream) 406 (only the first value is read) accepted

Expected

RFC 9110 §8.3.1 says the type, subtype and parameter names are case-insensitive. §5.3 allows a list-valued field like Accept to be sent as several field lines, which are equivalent to one comma-joined line. §12.5.1 says q=0 marks a type as not acceptable. Comparing parsed media types would cover all of these. For example: split on , across every Accept value, take the part before ;, trim it, compare with eq_ignore_ascii_case, and skip entries whose q is 0.

Impact

Low. Mainstream clients send lowercase values on a single line, so they work. A proxy or client that normalises header case, or splits Accept into separate lines, gets refused. The prefix and substring matches also let a non-JSON Content-Type through to the JSON deserialiser. That then fails later, with a less useful error.

Repro

curl -i -X POST http://127.0.0.1:8000/mcp \
  -H 'Content-Type: Application/JSON' \
  -H 'Accept: application/json, text/event-stream' \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
# HTTP/1.1 415 Unsupported Media Type

The check runs before the body is read, so the body and protocol headers don't matter.

AI disclosure: written with Claude Code. I reviewed it.

Vorherrschende Sprache
Rust
Sterne
4.1k
Forks
694
Ø Merge
4 T. 9 Std.
Gemergte PRs (30 T.)
41

Entwicklungsumgebung

In Codespaces öffnen

Startet den Dev-Container des Projekts im Browser, mit Ihrem eigenen GitHub-Konto.

Erste Schritte

  1. Lesen Sie das ganze Issue und danach den Beitragsleitfaden des Projekts.
  2. Schreiben Sie ins Issue, dass Sie es übernehmen — das erspart doppelte Arbeit.
  3. Forken Sie das Repository und arbeiten Sie in einem Branch.
  4. Öffnen Sie einen Pull Request, der die Issue-Nummer nennt.

Mehr aus modelcontextprotocol/rust-sdk

Alle Issues in modelcontextprotocol/rust-sdk

Ähnliche Issues

Weitere Issues zu Rust

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.