Skip to content

Commit bf3ff50

Browse files
ankitm123findleyr
authored andcommitted
mcp: remove json-rpc batching for more recent protocol versions
JSON-RPC batching support is removed for protocol versions greater than or equal to protocolVersion20250618 Fixes #21
1 parent 872b437 commit bf3ff50

File tree

2 files changed

+52
-7
lines changed

2 files changed

+52
-7
lines changed

mcp/streamable.go

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -614,17 +614,22 @@ func (c *streamableServerConn) servePOST(w http.ResponseWriter, req *http.Reques
614614
http.Error(w, "POST requires a non-empty body", http.StatusBadRequest)
615615
return
616616
}
617-
// TODO(#21): if the negotiated protocol version is 2025-06-18 or later,
618-
// we should not allow batching here.
619-
//
620-
// This also requires access to the negotiated version, which would either be
621-
// set by the MCP-Protocol-Version header, or would require peeking into the
622-
// session.
623-
incoming, _, err := readBatch(body)
617+
incoming, isBatch, err := readBatch(body)
624618
if err != nil {
625619
http.Error(w, fmt.Sprintf("malformed payload: %v", err), http.StatusBadRequest)
626620
return
627621
}
622+
623+
protocolVersion := req.Header.Get(protocolVersionHeader)
624+
if protocolVersion == "" {
625+
protocolVersion = protocolVersion20250326
626+
}
627+
628+
if isBatch && protocolVersion >= protocolVersion20250618 {
629+
http.Error(w, fmt.Sprintf("JSON-RPC batching is not supported in %s and later (request version: %s)", protocolVersion20250618, protocolVersion), http.StatusBadRequest)
630+
return
631+
}
632+
628633
requests := make(map[jsonrpc.ID]struct{})
629634
tokenInfo := auth.TokenInfoFromContext(req.Context())
630635
isInitialize := false

mcp/streamable_test.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -647,6 +647,46 @@ func TestStreamableServerTransport(t *testing.T) {
647647
},
648648
},
649649
},
650+
{
651+
name: "batch rejected on 2025-06-18",
652+
requests: []streamableRequest{
653+
initialize,
654+
initialized,
655+
{
656+
method: "POST",
657+
// Explicitly set the protocol version header
658+
headers: http.Header{"MCP-Protocol-Version": {"2025-06-18"}},
659+
// Two messages => batch. Expect reject.
660+
messages: []jsonrpc.Message{
661+
req(101, "tools/call", &CallToolParams{Name: "tool"}),
662+
req(102, "tools/call", &CallToolParams{Name: "tool"}),
663+
},
664+
wantStatusCode: http.StatusBadRequest,
665+
wantBodyContaining: "batch",
666+
},
667+
},
668+
},
669+
{
670+
name: "batch accepted on 2025-03-26",
671+
requests: []streamableRequest{
672+
initialize,
673+
initialized,
674+
{
675+
method: "POST",
676+
headers: http.Header{"MCP-Protocol-Version": {"2025-03-26"}},
677+
// Two messages => batch. Expect OK with two responses in order.
678+
messages: []jsonrpc.Message{
679+
req(201, "tools/call", &CallToolParams{Name: "tool"}),
680+
req(202, "tools/call", &CallToolParams{Name: "tool"}),
681+
},
682+
wantStatusCode: http.StatusOK,
683+
wantMessages: []jsonrpc.Message{
684+
resp(201, &CallToolResult{Content: []Content{}}, nil),
685+
resp(202, &CallToolResult{Content: []Content{}}, nil),
686+
},
687+
},
688+
},
689+
},
650690
{
651691
name: "tool notification",
652692
tool: func(t *testing.T, ctx context.Context, ss *ServerSession) {

0 commit comments

Comments
 (0)