modelcontextprotocol / modelcontextprotocol/java-sdk

Streamable HTTP server accepts POST requests with non-JSON request Content-Type

Aperta
#961 0 commenti 0 reazioni 0 assegnatari Vedi su GitHub

Nessuno ha ancora preso questa issue.

enhancement needs confirmation P3
Lingua principale
Java
Stelle
3.7k
Fork
1.1k
Merge medio
1g 15h
PR unite (30g)
9

Descrizione

Bug description

The Java SDK Streamable HTTP server accepts POST requests whose body is a valid JSON-RPC message even when the request Content-Type is missing or set to a non-JSON media type such as text/plain or application/x-www-form-urlencoded. These requests are processed normally and return HTTP 200.

I do not think the spec currently makes this requirement explicit. The MCP Streamable HTTP spec for 2025-11-25 requires POST request bodies to be JSON-RPC messages and requires the client Accept header to include both application/json and text/event-stream, but it does not explicitly say that servers must return HTTP 415 for a missing or non-JSON request Content-Type. I am filing this as an interoperability and hardening issue: if the body is JSON-RPC, the Java SDK currently accepts it regardless of the declared request media type.

In HttpServletStreamableServerTransportProvider, the POST handler validates the Accept header, then calls McpSchema.deserializeJsonRpcMessage(jsonMapper, body.toString()). I did not find a request Content-Type check before dispatch. This matches the observed behavior.

Environment

  • Repository: modelcontextprotocol/java-sdk
  • stable version: v1.1.2 (e9e1a2f34dedb72008d90e9919052d46eb2b701c, pinned 2026-05-03)
  • main snapshot: from 2026-05-15 (c09ee67f60260bd258b1a1aab9315a647a239d86, v0.6.0-355-gc09ee67f)
  • Transport: Streamable HTTP server, stateful mode
  • Java runtime used for repro: OpenJDK 21.0.10
  • SDK build target: Java 17 (java.version, maven.compiler.source, and maven.compiler.target are set to 17 in the SDK pom.xml)

Steps to reproduce

  1. Start a Java SDK Streamable HTTP server.
  2. Complete a normal initialize request and send notifications/initialized with the returned Mcp-Session-Id.
  3. Send a JSON-RPC request body with Content-Type: text/plain.
  4. Repeat with Content-Type: application/x-www-form-urlencoded.
  5. Repeat with the Content-Type header omitted.
  6. Observe that all three non-JSON or missing-content-type requests are dispatched and return HTTP 200.

In my retained logs, both stable and current behaved the same way:

Content-Type omitted: HTTP 200, request dispatched
Content-Type text/plain: HTTP 200, request dispatched
Content-Type application/x-www-form-urlencoded: HTTP 200, request dispatched
Content-Type application/json; charset=utf-8: HTTP 200, request dispatched

Expected behavior

I would expect the Streamable HTTP server to reject POST requests whose request Content-Type is missing or not a JSON media type before dispatching the JSON-RPC message, for example with HTTP 415 Unsupported Media Type or another clear 4xx transport error.

If accepting JSON bodies under non-JSON media types is intentional, it would be helpful to document that behavior explicitly, because other SDK server implementations reject the same probes and because accepting text/plain can matter for browser/CORS hardening.

Minimal Complete Reproducible example

Set ENDPOINT to a Java SDK Streamable HTTP endpoint:

ENDPOINT=http://127.0.0.1:8080/mcp

Initialize and copy the returned Mcp-Session-Id header into SID:

curl -i -sS --http1.1 -X POST "$ENDPOINT" \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -H 'MCP-Protocol-Version: 2025-11-25' \
  --data '{"jsonrpc":"2.0","id":"init-1","method":"initialize","params":{"protocolVersion":"2025-11-25","capabilities":{},"clientInfo":{"name":"content-type-repro","version":"0.1.0"}}}'

Send the initialized notification:

curl -i -sS --http1.1 -X POST "$ENDPOINT" \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -H 'MCP-Protocol-Version: 2025-11-25' \
  -H "Mcp-Session-Id: $SID" \
  --data '{"jsonrpc":"2.0","method":"notifications/initialized","params":{}}'

Send a normal JSON-RPC request, but declare it as text/plain:

curl -i -sS --http1.1 -X POST "$ENDPOINT" \
  -H 'Content-Type: text/plain' \
  -H 'Accept: application/json, text/event-stream' \
  -H 'MCP-Protocol-Version: 2025-11-25' \
  -H "Mcp-Session-Id: $SID" \
  --data '{"jsonrpc":"2.0","id":"ct-1","method":"tools/list","params":{}}'

Observed result:

HTTP/1.1 200 OK
Content-Type: text/event-stream;charset=UTF-8

id: ...
event: message
data: {"jsonrpc":"2.0","id":"ct-1","result":{"tools":[...]}}

The same behavior is reproducible with Content-Type: application/x-www-form-urlencoded and with the Content-Type header omitted.

Guida per i contributori

Apri la guida per i contributori

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Direzione di ricerca

Iniziare in HttpServletStreamableServerTransportProvider, nel gestore POST di Streamable HTTP, dove l’intestazione Accept viene controllata prima della chiamata a McpSchema.deserializeJsonRpcMessage. Riprodurre i casi con l’intestazione omessa, text/plain e application/x-www-form-urlencoded usando i comandi curl forniti, quindi verificare che i tipi di media della richiesta non validi o mancanti vengano rifiutati prima del dispatch JSON-RPC, mentre application/json continua a funzionare.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Valutazione

Stack tecnologico
java
Ambito
api, backend
Tipo di issue
Bug
Difficoltà
3/5
Tempo stimato
1-2 giorni
Stato di attività
Tranquilla
Chiarezza
Abbastanza chiara
Idoneità per principianti
65/100

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.