Support JSON response mode for StreamableHTTPTransport#328
Merged
koic merged 1 commit intomodelcontextprotocol:mainfrom Apr 23, 2026
Merged
Support JSON response mode for StreamableHTTPTransport#328koic merged 1 commit intomodelcontextprotocol:mainfrom
StreamableHTTPTransport#328koic merged 1 commit intomodelcontextprotocol:mainfrom
Conversation
## Motivation and Context The MCP Streamable HTTP specification allows servers to return POST responses as either `text/event-stream` (SSE) or `application/json`: > If the input is a JSON-RPC request, the server MUST either return `Content-Type: text/event-stream`, > to initiate an SSE stream, or `Content-Type: application/json`, to return one JSON object. See: https://modelcontextprotocol.io/specification/2025-11-25/basic/transports#sending-messages-to-the-server The TypeScript and Python SDKs support a configurable JSON response mode via `enableJsonResponse` / `is_json_response_enabled`. JSON response mode is suitable for simple tool servers that do not need server-initiated requests. It avoids SSE framing overhead and returns a single JSON object for the POST response. ## Behavior - POST responses use `Content-Type: application/json` and return a single JSON object. - The POST `Accept` header requirement is relaxed to `application/json` only (matching the Python SDK's lenient behavior). - Request-scoped notifications (`progress`, `log`) cannot ride along with the single-object response and are silently dropped. - Session-scoped standalone notifications (`resources/updated`, `elicitation/complete`) and broadcast notifications (`tools/list_changed`, etc.) continue to flow to clients connected to the GET SSE stream. - All server-to-client requests (`sampling/createMessage`, `roots/list`, `elicitation/create`) raise an error in JSON response mode. - Combines with `stateless: true` for simple single-response servers without session tracking. ## How Has This Been Tested? Added tests for JSON response mode: - POST request returns `application/json` response - Accept header validation requires only `application/json` - Returns 406 when Accept header is missing - Accepts wildcard `*/*` in Accept header - Request-scoped notifications (progress, log) during tool execution are silently dropped - Request-scoped notifications do not leak to GET SSE even when connected - Session-scoped standalone notifications are delivered via GET SSE - Broadcast notifications are delivered via GET SSE - `send_request` raises for `sampling/createMessage`, `roots/list`, `elicitation/create` - Combined with `stateless: true`: POST returns JSON without a session ID, GET returns 405 ## Breaking Changes None. JSON response mode is opt-in via `enable_json_response: true`. The default behavior (SSE responses) is unchanged.
26a87ed to
017b0bb
Compare
atesgoral
approved these changes
Apr 23, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Motivation and Context
The MCP Streamable HTTP specification allows servers to return POST responses as either
text/event-stream(SSE) orapplication/json:See: https://modelcontextprotocol.io/specification/2025-11-25/basic/transports#sending-messages-to-the-server
The TypeScript and Python SDKs support a configurable JSON response mode via
enableJsonResponse/is_json_response_enabled.JSON response mode is suitable for simple tool servers that do not need server-initiated requests. It avoids SSE framing overhead and returns a single JSON object for the POST response.
Behavior
Content-Type: application/jsonand return a single JSON object.Acceptheader requirement is relaxed toapplication/jsononly (matching the Python SDK's lenient behavior).progress,log) cannot ride along with the single-object response and are silently dropped.resources/updated,elicitation/complete) and broadcast notifications (tools/list_changed, etc.) continue to flow to clients connected to the GET SSE stream.sampling/createMessage,roots/list,elicitation/create) raise an error in JSON response mode.stateless: truefor simple single-response servers without session tracking.How Has This Been Tested?
Added tests for JSON response mode:
application/jsonresponseapplication/json*/*in Accept headersend_requestraises forsampling/createMessage,roots/list,elicitation/createstateless: true: POST returns JSON without a session ID, GET returns 405Breaking Changes
None. JSON response mode is opt-in via
enable_json_response: true. The default behavior (SSE responses) is unchanged.Types of changes
Checklist