modelcontextprotocol / modelcontextprotocol/java-sdk
Streamable HTTP server accepts POST requests with non-JSON request Content-Type
Nobody has claimed this yet.
- Dominant language
- Java
- Stars
- 3.7k
- Forks
- 1.1k
- Avg merge
- 1d 15h
- Merged PRs (30d)
- 9
Description
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) mainsnapshot: 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, andmaven.compiler.targetare set to17in the SDKpom.xml)
Steps to reproduce
- Start a Java SDK Streamable HTTP server.
- Complete a normal
initializerequest and sendnotifications/initializedwith the returnedMcp-Session-Id. - Send a JSON-RPC request body with
Content-Type: text/plain. - Repeat with
Content-Type: application/x-www-form-urlencoded. - Repeat with the
Content-Typeheader omitted. - 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.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in HttpServletStreamableServerTransportProvider at the Streamable HTTP POST handler, where the Accept header is checked before McpSchema.deserializeJsonRpcMessage is called. Reproduce the omitted, text/plain, and application/x-www-form-urlencoded cases with the provided curl commands, then verify that invalid or missing request media types are rejected before JSON-RPC dispatch while application/json continues to work.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java
- Domain
- api, backend
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 65/100