Describe the bug
A server served via NewSSEHandler advertises 2026-07-28 in its server/discover supportedVersions, so a Modern-first client negotiates that revision over the deprecated 2024-11-05 HTTP+SSE binding.
MCP 2026-07-28 defines exactly two transport bindings — stdio and Streamable HTTP. It says nothing about HTTP+SSE, so advertising it from the SSE handler tells clients the server speaks a revision over a binding that revision does not define.
Cause
filterSupportedVersions (mcp/server.go:915) returns every SDK-supported version unless the Transport implements ProtocolVersionSupporter:
func filterSupportedVersions(t Transport) []string {
pvs, ok := t.(ProtocolVersionSupporter)
if !ok {
return slices.Clone(supportedProtocolVersions)
}
...
}
SSEServerTransport does not implement it. Only the streamable transport does (mcp/streamable.go). So ss.supportedVersions (mcp/server.go:1390) ends up containing 2026-07-28 for SSE sessions, and server/discover reports it (mcp/server.go:904).
To Reproduce
- Build a
Server and serve it with mcp.NewSSEHandler(getServer, nil).
- Connect a client and issue
server/discover.
supportedVersions contains 2026-07-28.
Expected behavior
The SSE handler's sessions should advertise only the revisions that define the HTTP+SSE binding — i.e. exclude 2026-07-28.
Suggested fix
Have SSEServerTransport implement ProtocolVersionSupporter:
// SupportsProtocolVersion reports whether the transport can serve the given
// protocol version. MCP 2026-07-28 defines only the stdio and Streamable HTTP
// bindings, so the (deprecated) HTTP+SSE transport does not serve it.
func (t *SSEServerTransport) SupportsProtocolVersion(version string) bool {
return version != protocolVersion20260728
}
That is the smallest change and matches how the streamable transport already gates itself. Note there is currently no way for an SDK consumer to work around this: SSEHandler.ServeHTTP constructs the SSEServerTransport internally and calls server.Connect(ctx, transport, nil) (mcp/sse.go:274), and SSEOptions exposes only DisableLocalhostProtection — so a wrapper cannot supply or decorate the transport to add the interface.
Additional context
Found while adopting v1.7.0-pre.3 in a shim library that offers both an SSE and a Streamable HTTP server. Impact for us is low in practice — our Modern client path only ever POSTs to a configured Streamable endpoint and so never reaches the SSE message endpoint — but the advertisement is observable to any client that speaks to an SSE-fronted server, and it makes version negotiation report something the binding cannot honour.
Happy to send a PR if the suggested fix looks right.
Describe the bug
A server served via
NewSSEHandleradvertises2026-07-28in itsserver/discoversupportedVersions, so a Modern-first client negotiates that revision over the deprecated 2024-11-05 HTTP+SSE binding.MCP 2026-07-28 defines exactly two transport bindings — stdio and Streamable HTTP. It says nothing about HTTP+SSE, so advertising it from the SSE handler tells clients the server speaks a revision over a binding that revision does not define.
Cause
filterSupportedVersions(mcp/server.go:915) returns every SDK-supported version unless theTransportimplementsProtocolVersionSupporter:SSEServerTransportdoes not implement it. Only the streamable transport does (mcp/streamable.go). Soss.supportedVersions(mcp/server.go:1390) ends up containing2026-07-28for SSE sessions, andserver/discoverreports it (mcp/server.go:904).To Reproduce
Serverand serve it withmcp.NewSSEHandler(getServer, nil).server/discover.supportedVersionscontains2026-07-28.Expected behavior
The SSE handler's sessions should advertise only the revisions that define the HTTP+SSE binding — i.e. exclude
2026-07-28.Suggested fix
Have
SSEServerTransportimplementProtocolVersionSupporter:That is the smallest change and matches how the streamable transport already gates itself. Note there is currently no way for an SDK consumer to work around this:
SSEHandler.ServeHTTPconstructs theSSEServerTransportinternally and callsserver.Connect(ctx, transport, nil)(mcp/sse.go:274), andSSEOptionsexposes onlyDisableLocalhostProtection— so a wrapper cannot supply or decorate the transport to add the interface.Additional context
Found while adopting v1.7.0-pre.3 in a shim library that offers both an SSE and a Streamable HTTP server. Impact for us is low in practice — our Modern client path only ever POSTs to a configured Streamable endpoint and so never reaches the SSE message endpoint — but the advertisement is observable to any client that speaks to an SSE-fronted server, and it makes version negotiation report something the binding cannot honour.
Happy to send a PR if the suggested fix looks right.