mcp: bump protocol version from 2026-06-30 to 2026-07-28 (#1015)

The new official date for the protocol version has been moved to
'2026-07-28'. Update all the references in the code of the old version.
This commit is contained in:
Guglielmo Colombo 2026-06-22 09:53:04 +02:00 • committed by GitHub
commit 17029489ff
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 137 additions and 137 deletions

View file

@ -165,7 +165,7 @@ type ClientOptions struct {
// If non-zero, defines an interval for regular "ping" requests.
// If the peer fails to respond to pings originating from the keepalive check,
// the session is automatically closed.
// NOTE: The keepalive feature is only available for protocol versions < 2026-06-30
// NOTE: The keepalive feature is only available for protocol versions < 2026-07-28
KeepAlive time.Duration
// KeepAliveFailureThreshold is the number of consecutive keepalive ping
// failures tolerated before the session is closed. A value of 0 or 1
@ -285,7 +285,7 @@ func (c *Client) Connect(ctx context.Context, t Transport, opts *ClientSessionOp
protocolVersion = opts.protocolVersion
}
if protocolVersion >= protocolVersion20260630 {
if protocolVersion >= protocolVersion20260728 {
// Per SEP-2575, try the stateless server/discover RPC first. If the server
// signals it doesn't support it, fall back to the legacy initialize
// handshake.
@ -309,7 +309,7 @@ func (c *Client) Connect(ctx context.Context, t Transport, opts *ClientSessionOp
if errors.As(err, &werr) && werr.Code == CodeUnsupportedProtocolVersion && werr.Data != nil {
var data UnsupportedProtocolVersionData
if err := json.Unmarshal(werr.Data, &data); err == nil {
if negotiatedVersion := negotiateMutuallySupportedVersion(data.Supported); negotiatedVersion != "" && negotiatedVersion >= protocolVersion20260630 {
if negotiatedVersion := negotiateMutuallySupportedVersion(data.Supported); negotiatedVersion != "" && negotiatedVersion >= protocolVersion20260728 {
discoverCtx = context.WithValue(ctx, protocolVersionContextKey{}, negotiatedVersion)
continue
}
@ -381,7 +381,7 @@ func (c *Client) discover(ctx context.Context, cs *ClientSession) (*InitializeRe
} else {
negotiated = negotiateMutuallySupportedVersion(res.SupportedVersions)
}
if negotiated == "" || negotiated < protocolVersion20260630 {
if negotiated == "" || negotiated < protocolVersion20260728 {
// If there is no overlap, fall back to initialize so version
// negotiation can happen via the legacy path.
return nil, jsonrpc2.ErrUnsupportedProtocolVersion
@ -436,11 +436,11 @@ type clientSessionState struct {
func (cs *ClientSession) InitializeResult() *InitializeResult { return cs.state.InitializeResult }
// usesNewProtocol reports whether this session has negotiated a protocol
// version >= 2026-06-30, which requires the SEP-2575 per-request `_meta`
// version >= 2026-07-28, which requires the SEP-2575 per-request `_meta`
// triple on every outgoing request.
func (cs *ClientSession) usesNewProtocol() bool {
res := cs.state.InitializeResult
return res != nil && res.ProtocolVersion >= protocolVersion20260630
return res != nil && res.ProtocolVersion >= protocolVersion20260728
}
// injectRequestMeta populates the SEP-2575 per-request `_meta` triple

View file

@ -642,9 +642,9 @@ func TestClientCapabilitiesOverWire(t *testing.T) {
// don't overlap with the SDK. The test then asserts the resulting session
// state and whether the legacy initialize handshake ran.
func TestClientConnectDiscover(t *testing.T) {
// Temporarily enable 2026-06-30 support in the SDK for this test
// Temporarily enable 2026-07-28 support in the SDK for this test
oldSupported := supportedProtocolVersions
supportedProtocolVersions = append([]string{protocolVersion20260630}, supportedProtocolVersions...)
supportedProtocolVersions = append([]string{protocolVersion20260728}, supportedProtocolVersions...)
t.Cleanup(func() {
supportedProtocolVersions = oldSupported
})
@ -668,7 +668,7 @@ func TestClientConnectDiscover(t *testing.T) {
name: "discover success skips initialize",
discoverHandler: func() (Result, error) {
return &DiscoverResult{
SupportedVersions: []string{protocolVersion20260630},
SupportedVersions: []string{protocolVersion20260728},
Capabilities: &ServerCapabilities{
Tools: &ToolCapabilities{ListChanged: true},
},
@ -676,7 +676,7 @@ func TestClientConnectDiscover(t *testing.T) {
}, nil
},
wantInitialize: false,
wantVersion: protocolVersion20260630,
wantVersion: protocolVersion20260728,
},
{
name: "method not found falls back to initialize",
@ -742,7 +742,7 @@ func TestClientConnectDiscover(t *testing.T) {
defer ss.Close()
c := NewClient(testImpl, nil)
cs, err := c.Connect(ctx, ct, &ClientSessionOptions{protocolVersion: protocolVersion20260630})
cs, err := c.Connect(ctx, ct, &ClientSessionOptions{protocolVersion: protocolVersion20260728})
if err != nil {
t.Fatalf("Connect: %v", err)
}
@ -770,7 +770,7 @@ func TestClientConnectDiscover(t *testing.T) {
// protocolVersion, clientInfo, and clientCapabilities.
func TestClientConnectDiscover_RequestContents(t *testing.T) {
orig := supportedProtocolVersions
supportedProtocolVersions = append([]string{protocolVersion20260630}, slices.Clone(orig)...)
supportedProtocolVersions = append([]string{protocolVersion20260728}, slices.Clone(orig)...)
t.Cleanup(func() { supportedProtocolVersions = orig })
ctx := context.Background()
@ -811,7 +811,7 @@ func TestClientConnectDiscover_RequestContents(t *testing.T) {
return nil, nil
},
})
cs, err := c.Connect(ctx, ct, &ClientSessionOptions{protocolVersion: protocolVersion20260630})
cs, err := c.Connect(ctx, ct, &ClientSessionOptions{protocolVersion: protocolVersion20260728})
if err != nil {
t.Fatalf("Connect: %v", err)
}
@ -822,8 +822,8 @@ func TestClientConnectDiscover_RequestContents(t *testing.T) {
}
meta := got.params.GetMeta()
if v, _ := meta[MetaKeyProtocolVersion].(string); v != protocolVersion20260630 {
t.Errorf("_meta[%s] = %q, want %q", MetaKeyProtocolVersion, v, protocolVersion20260630)
if v, _ := meta[MetaKeyProtocolVersion].(string); v != protocolVersion20260728 {
t.Errorf("_meta[%s] = %q, want %q", MetaKeyProtocolVersion, v, protocolVersion20260728)
}
// _meta values round-trip through JSON, so on the server side they
// arrive as map[string]any rather than the typed Go pointers we sent.
@ -849,7 +849,7 @@ func TestInMemory_E2E_DiscoverSuccess(t *testing.T) {
ctx := context.Background()
orig := supportedProtocolVersions
supportedProtocolVersions = append([]string{protocolVersion20260630}, slices.Clone(orig)...)
supportedProtocolVersions = append([]string{protocolVersion20260728}, slices.Clone(orig)...)
t.Cleanup(func() { supportedProtocolVersions = orig })
server := NewServer(&Implementation{Name: "stdio-like-server", Version: "v1"}, nil)
@ -861,7 +861,7 @@ func TestInMemory_E2E_DiscoverSuccess(t *testing.T) {
defer ss.Close()
client := NewClient(&Implementation{Name: "stdio-like-client", Version: "v1"}, nil)
cs, err := client.Connect(ctx, ct, &ClientSessionOptions{protocolVersion: protocolVersion20260630})
cs, err := client.Connect(ctx, ct, &ClientSessionOptions{protocolVersion: protocolVersion20260728})
if err != nil {
t.Fatalf("client.Connect: %v", err)
}
@ -871,9 +871,9 @@ func TestInMemory_E2E_DiscoverSuccess(t *testing.T) {
if ir == nil {
t.Fatal("InitializeResult is nil; discover should have populated it")
}
if ir.ProtocolVersion != protocolVersion20260630 {
if ir.ProtocolVersion != protocolVersion20260728 {
t.Errorf("InitializeResult.ProtocolVersion = %q, want %q (negotiated via discover, no initialize)",
ir.ProtocolVersion, protocolVersion20260630)
ir.ProtocolVersion, protocolVersion20260728)
}
if ir.ServerInfo == nil || ir.ServerInfo.Name != "stdio-like-server" {
t.Errorf("InitializeResult.ServerInfo = %+v, want name=stdio-like-server", ir.ServerInfo)
@ -887,13 +887,13 @@ func TestInMemory_E2E_DiscoverSuccess(t *testing.T) {
// TestInMemory_E2E_DiscoverFallback_NoOverlap verifies the fallback path
// over an InMemory (STDIO-equivalent) transport: the client probes with
// _meta.protocolVersion = 2026-06-30, but the server's supported list does
// _meta.protocolVersion = 2026-07-28, but the server's supported list does
// NOT include that version (the default for an SDK server that hasn't
// shimmed supportedProtocolVersions).
func TestInMemory_E2E_DiscoverFallback_NoOverlap(t *testing.T) {
ctx := context.Background()
orig := supportedProtocolVersions
supportedProtocolVersions = append([]string{protocolVersion20260630}, slices.Clone(orig)...)
supportedProtocolVersions = append([]string{protocolVersion20260728}, slices.Clone(orig)...)
t.Cleanup(func() { supportedProtocolVersions = orig })
server := NewServer(&Implementation{Name: "vpre-like-server", Version: "v1"}, nil)
@ -920,7 +920,7 @@ func TestInMemory_E2E_DiscoverFallback_NoOverlap(t *testing.T) {
defer ss.Close()
client := NewClient(&Implementation{Name: "new-client", Version: "v1"}, nil)
cs, err := client.Connect(ctx, ct, &ClientSessionOptions{protocolVersion: protocolVersion20260630})
cs, err := client.Connect(ctx, ct, &ClientSessionOptions{protocolVersion: protocolVersion20260728})
if err != nil {
t.Fatalf("client.Connect: %v", err)
}
@ -948,7 +948,7 @@ func TestInMemory_E2E_DiscoverFallback_MethodNotFound(t *testing.T) {
ctx := context.Background()
orig := supportedProtocolVersions
supportedProtocolVersions = append([]string{protocolVersion20260630}, slices.Clone(orig)...)
supportedProtocolVersions = append([]string{protocolVersion20260728}, slices.Clone(orig)...)
t.Cleanup(func() { supportedProtocolVersions = orig })
server := NewServer(&Implementation{Name: "vpre-server", Version: "v1"}, nil)
@ -969,7 +969,7 @@ func TestInMemory_E2E_DiscoverFallback_MethodNotFound(t *testing.T) {
defer ss.Close()
client := NewClient(&Implementation{Name: "new-client", Version: "v1"}, nil)
cs, err := client.Connect(ctx, ct, &ClientSessionOptions{protocolVersion: protocolVersion20260630})
cs, err := client.Connect(ctx, ct, &ClientSessionOptions{protocolVersion: protocolVersion20260728})
if err != nil {
t.Fatalf("client.Connect: %v", err)
}
@ -997,7 +997,7 @@ func TestInMemory_E2E_DiscoverFallback_UnsupportedProtocolVersion(t *testing.T)
ctx := context.Background()
orig := supportedProtocolVersions
supportedProtocolVersions = append([]string{protocolVersion20260630}, slices.Clone(orig)...)
supportedProtocolVersions = append([]string{protocolVersion20260728}, slices.Clone(orig)...)
t.Cleanup(func() { supportedProtocolVersions = orig })
server := NewServer(&Implementation{Name: "strict-server", Version: "v1"}, nil)
@ -1021,7 +1021,7 @@ func TestInMemory_E2E_DiscoverFallback_UnsupportedProtocolVersion(t *testing.T)
defer ss.Close()
client := NewClient(&Implementation{Name: "new-client", Version: "v1"}, nil)
cs, err := client.Connect(ctx, ct, &ClientSessionOptions{protocolVersion: protocolVersion20260630})
cs, err := client.Connect(ctx, ct, &ClientSessionOptions{protocolVersion: protocolVersion20260728})
if err != nil {
t.Fatalf("client.Connect: %v", err)
}
@ -1044,7 +1044,7 @@ func TestInMemory_E2E_DiscoverFallback_UnsupportedProtocolVersion(t *testing.T)
// selects a mutually supported version from that list and retries.
func TestClientConnectDiscover_UnsupportedVersionNegotiation(t *testing.T) {
oldSupported := supportedProtocolVersions
supportedProtocolVersions = append([]string{protocolVersion20260630}, slices.Clone(oldSupported)...)
supportedProtocolVersions = append([]string{protocolVersion20260728}, slices.Clone(oldSupported)...)
t.Cleanup(func() { supportedProtocolVersions = oldSupported })
ctx := context.Background()
@ -1095,8 +1095,8 @@ func TestClientConnectDiscover_UnsupportedVersionNegotiation(t *testing.T) {
if got, want := discoverCalls.Load(), int32(1); got != want {
t.Errorf("server/discover handler call count = %d, want %d (first probe is rejected by the dispatcher; only the retry reaches the handler)", got, want)
}
if got, _ := observedDiscoverVersion.Load().(string); got != protocolVersion20260630 {
t.Errorf("retry discover requested version = %q, want %q (highest mutually supported version)", got, protocolVersion20260630)
if got, _ := observedDiscoverVersion.Load().(string); got != protocolVersion20260728 {
t.Errorf("retry discover requested version = %q, want %q (highest mutually supported version)", got, protocolVersion20260728)
}
if gotInitialize.Load() {
t.Error("legacy initialize handshake ran, but negotiated discover should have succeeded")
@ -1106,7 +1106,7 @@ func TestClientConnectDiscover_UnsupportedVersionNegotiation(t *testing.T) {
if ir == nil {
t.Fatal("InitializeResult is nil after Connect")
}
if got, want := ir.ProtocolVersion, protocolVersion20260630; got != want {
if got, want := ir.ProtocolVersion, protocolVersion20260728; got != want {
t.Errorf("InitializeResult.ProtocolVersion = %q, want %q", got, want)
}
}

View file

@ -67,7 +67,7 @@ func clientSupportsMultiRoundTrip(ss *ServerSession) bool {
if iparams := ss.InitializeParams(); iparams != nil {
protocolVersion = iparams.ProtocolVersion
}
return protocolVersion >= protocolVersion20260630
return protocolVersion >= protocolVersion20260728
}
func clientMultiRoundTripMiddleware() Middleware {

View file

@ -22,7 +22,7 @@ func TestMultiRoundTrip_ManualRetry(t *testing.T) {
}
orig := supportedProtocolVersions
supportedProtocolVersions = append(slices.Clone(orig), protocolVersion20260630)
supportedProtocolVersions = append(slices.Clone(orig), protocolVersion20260728)
t.Cleanup(func() { supportedProtocolVersions = orig })
ctx := context.Background()
@ -94,7 +94,7 @@ func TestMultiRoundTrip_ManualRetry(t *testing.T) {
func TestMultiRoundTrip_AutoRetry(t *testing.T) {
orig := supportedProtocolVersions
supportedProtocolVersions = append(slices.Clone(orig), protocolVersion20260630)
supportedProtocolVersions = append(slices.Clone(orig), protocolVersion20260728)
t.Cleanup(func() { supportedProtocolVersions = orig })
tests := []struct {
@ -219,7 +219,7 @@ func TestMultiRoundTrip_MaxRetries(t *testing.T) {
},
}
orig := supportedProtocolVersions
supportedProtocolVersions = append(slices.Clone(orig), protocolVersion20260630)
supportedProtocolVersions = append(slices.Clone(orig), protocolVersion20260728)
t.Cleanup(func() { supportedProtocolVersions = orig })
for _, tc := range testCases {
@ -339,7 +339,7 @@ func TestMultiRoundTrip_ServerMiddleware(t *testing.T) {
func TestMultiRoundTrip_GetPrompt_AutoRetry(t *testing.T) {
orig := supportedProtocolVersions
supportedProtocolVersions = append(slices.Clone(orig), protocolVersion20260630)
supportedProtocolVersions = append(slices.Clone(orig), protocolVersion20260728)
t.Cleanup(func() { supportedProtocolVersions = orig })
ctx := context.Background()
@ -381,7 +381,7 @@ func TestMultiRoundTrip_GetPrompt_AutoRetry(t *testing.T) {
func TestMultiRoundTrip_GetPrompt_ManualRetry(t *testing.T) {
orig := supportedProtocolVersions
supportedProtocolVersions = append(slices.Clone(orig), protocolVersion20260630)
supportedProtocolVersions = append(slices.Clone(orig), protocolVersion20260728)
t.Cleanup(func() { supportedProtocolVersions = orig })
ctx := context.Background()
@ -433,7 +433,7 @@ func TestMultiRoundTrip_GetPrompt_ManualRetry(t *testing.T) {
func TestMultiRoundTrip_ReadResource_AutoRetry(t *testing.T) {
orig := supportedProtocolVersions
supportedProtocolVersions = append(slices.Clone(orig), protocolVersion20260630)
supportedProtocolVersions = append(slices.Clone(orig), protocolVersion20260728)
t.Cleanup(func() { supportedProtocolVersions = orig })
ctx := context.Background()
@ -474,7 +474,7 @@ func TestMultiRoundTrip_ReadResource_AutoRetry(t *testing.T) {
func TestMultiRoundTrip_ReadResource_ManualRetry(t *testing.T) {
orig := supportedProtocolVersions
supportedProtocolVersions = append(slices.Clone(orig), protocolVersion20260630)
supportedProtocolVersions = append(slices.Clone(orig), protocolVersion20260728)
t.Cleanup(func() { supportedProtocolVersions = orig })
ctx := context.Background()
@ -536,7 +536,7 @@ func mustConnect(t *testing.T, s *Server, clientOpts *ClientOptions) *ClientSess
})
c := NewClient(testImpl, clientOpts)
cs, err := c.Connect(t.Context(), ct, &ClientSessionOptions{protocolVersion: protocolVersion20260630})
cs, err := c.Connect(t.Context(), ct, &ClientSessionOptions{protocolVersion: protocolVersion20260728})
if err != nil {
t.Fatalf("client.Connect() error = %v", err)
}

View file

@ -2138,7 +2138,7 @@ const (
methodUnsubscribe = "resources/unsubscribe"
)
// Per-request _meta field names for the >= 2026-06-30 protocol version.
// Per-request _meta field names for the >= 2026-07-28 protocol version.
//
// These keys appear inside a Params._meta map and carry information that
// previously came from the initialization handshake (SEP-2575).

View file

@ -1441,7 +1441,7 @@ func (ss *ServerSession) Elicit(ctx context.Context, params *ElicitParams) (*Eli
// logLevelContextKey carries the per-request log level from
// [ServerSession.handle] to [ServerSession.Log] for new-protocol
// (>= 2026-06-30) requests. The level is scoped to a single in-flight request
// (>= 2026-07-28) requests. The level is scoped to a single in-flight request
// — including handler goroutines that call [ServerSession.Log] concurrently —
// rather than to the session, which avoids races between concurrent requests
// and aligns with SEP-2575's per-request opt-in model. The value type is
@ -1450,7 +1450,7 @@ type logLevelContextKey struct{}
// Log sends a log message to the client.
//
// For new-protocol (>= 2026-06-30) requests, the level is taken from the
// For new-protocol (>= 2026-07-28) requests, the level is taken from the
// originating request's `_meta` field (SEP-2575); an absent or empty value
// suppresses the message per spec. For old-protocol requests, the level is
// taken from the session state set via `logging/setLevel`.
@ -1609,7 +1609,7 @@ func (ss *ServerSession) handle(ctx context.Context, req *jsonrpc.Request) (any,
case methodDiscover:
// In case of methodDiscover call the state.initializeParams is populated
// within the discover handle function to make sure the method is supported
// when the user is probing a pre-2026-06-30 server.
// when the user is probing a pre-2026-07-28 server.
default:
if !initialized && !validatedMeta.usesNewProtocol {
ss.server.opts.Logger.Error("method invalid during initialization", "method", req.Method)

View file

@ -1291,7 +1291,7 @@ func TestServerCapabilitiesOverWire(t *testing.T) {
// rejected with `Method not found` (-32601).
func TestServerSessionHandle_RejectsInitializeOnNewProtocol(t *testing.T) {
orig := supportedProtocolVersions
supportedProtocolVersions = append([]string{protocolVersion20260630}, slices.Clone(orig)...)
supportedProtocolVersions = append([]string{protocolVersion20260728}, slices.Clone(orig)...)
t.Cleanup(func() { supportedProtocolVersions = orig })
tests := []struct {
@ -1303,11 +1303,11 @@ func TestServerSessionHandle_RejectsInitializeOnNewProtocol(t *testing.T) {
name: "initialize with new-protocol _meta is rejected",
params: map[string]any{
"_meta": map[string]any{
MetaKeyProtocolVersion: protocolVersion20260630,
MetaKeyProtocolVersion: protocolVersion20260728,
MetaKeyClientInfo: map[string]any{"name": "c", "version": "1"},
MetaKeyClientCapabilities: map[string]any{},
},
"protocolVersion": protocolVersion20260630,
"protocolVersion": protocolVersion20260728,
},
wantReject: true,
},
@ -1372,11 +1372,11 @@ func TestServerSessionHandle_RejectsInitializeOnNewProtocol(t *testing.T) {
Method: methodInitialize,
Params: mustMarshal(map[string]any{
"_meta": map[string]any{
MetaKeyProtocolVersion: protocolVersion20260630,
MetaKeyProtocolVersion: protocolVersion20260728,
MetaKeyClientInfo: map[string]any{"name": "c", "version": "1"},
MetaKeyClientCapabilities: map[string]any{},
},
"protocolVersion": protocolVersion20260630,
"protocolVersion": protocolVersion20260728,
}),
}
_, handleErr := ss.handle(context.Background(), req)
@ -1408,12 +1408,12 @@ func TestServerSessionHandle_RejectsInitializeOnNewProtocol(t *testing.T) {
// protocol via `_meta.protocolVersion`.
func TestServerSessionHandle_RejectsRemovedMethodsOnNewProtocol(t *testing.T) {
orig := supportedProtocolVersions
supportedProtocolVersions = append([]string{protocolVersion20260630}, slices.Clone(orig)...)
supportedProtocolVersions = append([]string{protocolVersion20260728}, slices.Clone(orig)...)
t.Cleanup(func() { supportedProtocolVersions = orig })
newProtoMeta := map[string]any{
"_meta": map[string]any{
MetaKeyProtocolVersion: protocolVersion20260630,
MetaKeyProtocolVersion: protocolVersion20260728,
MetaKeyClientInfo: map[string]any{"name": "c", "version": "1"},
MetaKeyClientCapabilities: map[string]any{},
},

View file

@ -36,7 +36,7 @@ const (
// It is the version that the client sends in the initialization request, and
// the default version used by the server.
latestProtocolVersion = protocolVersion20251125
protocolVersion20260630 = "2026-06-30"
protocolVersion20260728 = "2026-07-28"
protocolVersion20251125 = "2025-11-25"
protocolVersion20250618 = "2025-06-18"
protocolVersion20250326 = "2025-03-26"
@ -504,7 +504,7 @@ type validatedMeta struct {
}
// validateRequestMeta inspects a JSON-RPC request to detect whether it follows
// the >= 2026-06-30 protocol via the `_meta` field.
// the >= 2026-07-28 protocol via the `_meta` field.
// If the request has no _meta, or no protocolVersion in _meta, it returns a non-nil
// validatedMeta with usesNewProtocol set to false, and a nil error.
// If the request has a protocolVersion in _meta:
@ -518,7 +518,7 @@ func validateRequestMeta(req *jsonrpc.Request) (*validatedMeta, error) {
return &validatedMeta{usesNewProtocol: false, initializeParams: nil}, nil
}
protocolVersion, ok := meta[MetaKeyProtocolVersion].(string)
if !ok || protocolVersion < protocolVersion20260630 {
if !ok || protocolVersion < protocolVersion20260728 {
return &validatedMeta{usesNewProtocol: false, initializeParams: nil}, nil
}
// Notifications do not carry full client identity.
@ -585,7 +585,7 @@ type RequestExtra struct {
// to configure the reconnection delay.
//
// [SEP-1699]: https://github.com/modelcontextprotocol/modelcontextprotocol/issues/1699
// This mechanism is deprecated in protocol version 2026-06-30 as the resumability
// This mechanism is deprecated in protocol version 2026-07-28 as the resumability
// feature is removed.
CloseSSEStream func(CloseSSEStreamArgs)
}
@ -611,7 +611,7 @@ func (r *ServerRequest[P]) GetExtra() *RequestExtra { return r.Extra }
// ProtocolVersion returns the protocol version negotiated for this request.
//
// For requests following the >= 2026-06-30 protocol, the value is read from
// For requests following the >= 2026-07-28 protocol, the value is read from
// the per-request `_meta` field. For older protocol requests, the value falls
// back to the session-level [InitializeParams] established during the
// initialize handshake.
@ -631,7 +631,7 @@ func (r *ServerRequest[P]) ProtocolVersion() string {
// ClientInfo returns the [Implementation] identifying the calling client.
//
// For requests following the >= 2026-06-30 protocol, the value is read from
// For requests following the >= 2026-07-28 protocol, the value is read from
// the per-request `_meta` field. For older protocol requests, the value falls
// back to the session-level [InitializeParams].
func (r *ServerRequest[P]) ClientInfo() *Implementation {
@ -650,7 +650,7 @@ func (r *ServerRequest[P]) ClientInfo() *Implementation {
// ClientCapabilities returns the [ClientCapabilities] of the calling client.
//
// For requests following the >= 2026-06-30 protocol, the value is read from
// For requests following the >= 2026-07-28 protocol, the value is read from
// the per-request `_meta` field. For older protocol requests, the value falls
// back to the session-level [InitializeParams].
func (r *ServerRequest[P]) ClientCapabilities() *ClientCapabilities {

View file

@ -50,7 +50,7 @@ func TestValidateRequestMeta(t *testing.T) {
method: methodCallTool,
params: map[string]any{
"_meta": map[string]any{
MetaKeyProtocolVersion: protocolVersion20260630,
MetaKeyProtocolVersion: protocolVersion20260728,
MetaKeyClientInfo: map[string]any{"name": "c", "version": "1"},
MetaKeyClientCapabilities: map[string]any{},
},
@ -63,7 +63,7 @@ func TestValidateRequestMeta(t *testing.T) {
method: methodCallTool,
params: map[string]any{
"_meta": map[string]any{
MetaKeyProtocolVersion: protocolVersion20260630,
MetaKeyProtocolVersion: protocolVersion20260728,
MetaKeyClientCapabilities: map[string]any{},
},
"name": "x",
@ -76,7 +76,7 @@ func TestValidateRequestMeta(t *testing.T) {
method: methodCallTool,
params: map[string]any{
"_meta": map[string]any{
MetaKeyProtocolVersion: protocolVersion20260630,
MetaKeyProtocolVersion: protocolVersion20260728,
MetaKeyClientInfo: map[string]any{"name": "c", "version": "1"},
},
"name": "x",
@ -90,7 +90,7 @@ func TestValidateRequestMeta(t *testing.T) {
isNotification: true,
params: map[string]any{
"_meta": map[string]any{
MetaKeyProtocolVersion: protocolVersion20260630,
MetaKeyProtocolVersion: protocolVersion20260728,
},
"requestId": "r1",
},
@ -107,7 +107,7 @@ func TestValidateRequestMeta(t *testing.T) {
method: methodCallTool,
params: map[string]any{
"_meta": map[string]any{
MetaKeyProtocolVersion: protocolVersion20260630,
MetaKeyProtocolVersion: protocolVersion20260728,
MetaKeyClientInfo: map[string]any{"name": "c", "version": "1"},
MetaKeyClientCapabilities: map[string]any{},
MetaKeyLogLevel: "warning",
@ -122,7 +122,7 @@ func TestValidateRequestMeta(t *testing.T) {
method: methodCallTool,
params: map[string]any{
"_meta": map[string]any{
MetaKeyProtocolVersion: protocolVersion20260630,
MetaKeyProtocolVersion: protocolVersion20260728,
MetaKeyClientInfo: map[string]any{"name": "c", "version": "1"},
MetaKeyClientCapabilities: map[string]any{},
},
@ -190,15 +190,15 @@ func TestServerRequest_PerRequestAccessors(t *testing.T) {
info := &Implementation{Name: "c", Version: "1"}
params := &CallToolParamsRaw{
Meta: Meta{
MetaKeyProtocolVersion: protocolVersion20260630,
MetaKeyProtocolVersion: protocolVersion20260728,
MetaKeyClientInfo: info,
MetaKeyClientCapabilities: caps,
},
Name: "x",
}
req := &ServerRequest[*CallToolParamsRaw]{Params: params}
if got := req.ProtocolVersion(); got != protocolVersion20260630 {
t.Errorf("ProtocolVersion = %q, want %q", got, protocolVersion20260630)
if got := req.ProtocolVersion(); got != protocolVersion20260728 {
t.Errorf("ProtocolVersion = %q, want %q", got, protocolVersion20260728)
}
if got := req.ClientInfo(); got == nil || got.Name != "c" {
t.Errorf("ClientInfo = %+v, want Name=c", got)
@ -213,7 +213,7 @@ func TestServerRequest_PerRequestAccessors_FromJSON(t *testing.T) {
// re-decode them into typed Go values.
raw := json.RawMessage(`{
"_meta": {
"io.modelcontextprotocol/protocolVersion": "2026-06-30",
"io.modelcontextprotocol/protocolVersion": "2026-07-28",
"io.modelcontextprotocol/clientInfo": {"name": "wire-client", "version": "9"},
"io.modelcontextprotocol/clientCapabilities": {"sampling": {}}
},
@ -224,7 +224,7 @@ func TestServerRequest_PerRequestAccessors_FromJSON(t *testing.T) {
t.Fatal(err)
}
req := &ServerRequest[*CallToolParamsRaw]{Params: &params}
if got, want := req.ProtocolVersion(), protocolVersion20260630; got != want {
if got, want := req.ProtocolVersion(), protocolVersion20260728; got != want {
t.Errorf("ProtocolVersion = %q, want %q", got, want)
}
gotInfo := req.ClientInfo()

View file

@ -314,7 +314,7 @@ func (h *StreamableHTTPHandler) ServeHTTP(w http.ResponseWriter, req *http.Reque
//
// [§2.7]: https://modelcontextprotocol.io/specification/2025-06-18/basic/transports#protocol-version-header
protocolVersion := req.Header.Get(protocolVersionHeader)
if protocolVersion != "" && !slices.Contains(supportedProtocolVersions, protocolVersion) && protocolVersion < protocolVersion20260630 {
if protocolVersion != "" && !slices.Contains(supportedProtocolVersions, protocolVersion) && protocolVersion < protocolVersion20260728 {
http.Error(w, fmt.Sprintf("Bad Request: Unsupported protocol version (supported versions: %s)", strings.Join(supportedProtocolVersions, ",")), http.StatusBadRequest)
return
}
@ -414,7 +414,7 @@ func (h *StreamableHTTPHandler) serveStatelessLegacyDELETE(w http.ResponseWriter
// ephemeralConnectOpts peeks at the request body to determine whether it
// contains an initialize or initialized message or whether the protocol version
// header indicates a protocol version >= 2026-06-30 (SEP-2575).
// header indicates a protocol version >= 2026-07-28 (SEP-2575).
//
// For old-protocol requests, default session state is synthesized so that
// the session's init gate doesn't reject the request.
@ -422,7 +422,7 @@ func (h *StreamableHTTPHandler) serveStatelessLegacyDELETE(w http.ResponseWriter
// It is used for both stateless servers and stateful servers with no session ID.
//
// The returned usesNewProtocol bool reports whether the protocol version
// header indicates a protocol version >= 2026-06-30 (SEP-2575).
// header indicates a protocol version >= 2026-07-28 (SEP-2575).
func (h *StreamableHTTPHandler) ephemeralConnectOpts(req *http.Request) (opts *ServerSessionOptions, usesNewProtocol bool, err error) {
protocolVersion := protocolVersionFromContext(req.Context())
if protocolVersion == "" {
@ -446,7 +446,7 @@ func (h *StreamableHTTPHandler) ephemeralConnectOpts(req *http.Request) (opts *S
case notificationInitialized:
hasInitialized = true
}
if protocolVersion >= protocolVersion20260630 {
if protocolVersion >= protocolVersion20260728 {
usesNewProtocol = true
}
}
@ -808,10 +808,10 @@ func (t *StreamableServerTransport) Connect(ctx context.Context) (Connection, er
}
// The streamable HTTP transport supports every legacy SDK protocol version,
// but the SEP-2575 >= 2026-06-30 protocol is only supported when the
// but the SEP-2575 >= 2026-07-28 protocol is only supported when the
// transport is configured as stateless.
func (t *StreamableServerTransport) SupportsProtocolVersion(version string) bool {
if version >= protocolVersion20260630 {
if version >= protocolVersion20260728 {
return t.Stateless && slices.Contains(supportedProtocolVersions, version)
}
return slices.Contains(supportedProtocolVersions, version)
@ -951,14 +951,14 @@ func (s *stream) release() {
// extractErrorStatus reports the HTTP status to send when the given
// outgoing message is a JSON-RPC error response under the SEP-2575 protocol
// (>= 2026-06-30).
// (>= 2026-07-28).
//
// Per SEP-2575:
// - MethodNotFound (-32601) MUST return HTTP 404.
// - InvalidParams (-32602) and UnsupportedProtocolVersion (-32004) MUST
// return HTTP 400.
func extractErrorStatus(ctx context.Context, msg jsonrpc.Message) int {
if protocolVersionFromContext(ctx) < protocolVersion20260630 {
if protocolVersionFromContext(ctx) < protocolVersion20260728 {
return 0
}
resp, ok := msg.(*jsonrpc.Response)
@ -986,7 +986,7 @@ func extractErrorStatus(ctx context.Context, msg jsonrpc.Message) int {
// requests have been responded to, the done channel is closed and set to nil.
//
// If overrideStatus is non-zero, data is treated as a SEP-2575 protocol-level
// error response (>= 2026-06-30): it is written as a single raw JSON-RPC
// error response (>= 2026-07-28): it is written as a single raw JSON-RPC
// response body with Content-Type: application/json and HTTP status
// overrideStatus.
//
@ -1065,7 +1065,7 @@ func (s *stream) doneLocked() bool {
}
func (c *streamableServerConn) newStream(ctx context.Context, requests map[jsonrpc.ID]struct{}, id string) (*stream, error) {
if c.eventStore != nil && protocolVersionFromContext(ctx) < protocolVersion20260630 {
if c.eventStore != nil && protocolVersionFromContext(ctx) < protocolVersion20260728 {
if err := c.eventStore.Open(ctx, c.sessionID, id); err != nil {
return nil, err
}
@ -1378,7 +1378,7 @@ func (c *streamableServerConn) servePOST(w http.ResponseWriter, req *http.Reques
// the HTTP request. If we didn't do this, a request with a bad method or
// missing ID could be silently swallowed.
if _, err := checkRequest(jreq, serverMethodInfos); err != nil {
if protocolVersion >= protocolVersion20260630 && errors.Is(err, jsonrpc2.ErrNotHandled) && jreq.IsCall() {
if protocolVersion >= protocolVersion20260728 && errors.Is(err, jsonrpc2.ErrNotHandled) && jreq.IsCall() {
writeJSONRPCError(w, http.StatusNotFound, jreq.ID, &jsonrpc.Error{
Code: jsonrpc.CodeMethodNotFound,
Message: err.Error(),
@ -1399,7 +1399,7 @@ func (c *streamableServerConn) servePOST(w http.ResponseWriter, req *http.Reques
// SEP-2575: requests carrying `_meta.protocolVersion` require the
// Mcp-Protocol-Version HTTP header to be present and to match the
// per-request `_meta.protocolVersion` value.
// The new (>= 2026-06-30) protocol is supported on the HTTP transport
// The new (>= 2026-07-28) protocol is supported on the HTTP transport
// only when [StreamableHTTPOptions.Stateless] is true.
//
// TODO: this validation can be moved within validateMcpHeaders.
@ -1407,7 +1407,7 @@ func (c *streamableServerConn) servePOST(w http.ResponseWriter, req *http.Reques
if meta := extractRequestMeta(jreq.Params); meta != nil {
metaVersion, _ = meta[MetaKeyProtocolVersion].(string)
}
if protocolVersion >= protocolVersion20260630 || metaVersion != "" {
if protocolVersion >= protocolVersion20260728 || metaVersion != "" {
// Extract again the protcol version from the context to see what the client
// is advertising in the Mcp-Protocol-Version HTTP header.
headerVersion := protocolVersionFromContext(req.Context())
@ -1462,8 +1462,8 @@ func (c *streamableServerConn) servePOST(w http.ResponseWriter, req *http.Reques
jreq.Extra.(*RequestExtra).CloseSSEStream = func(args CloseSSEStreamArgs) {
// This mechanism was designed to trigger client reconnection with
// Last-Event-ID for server-initiated disconnect scenarios. It is
// deprecated in protocol version 2026-06-30.
if protocolVersion >= protocolVersion20260630 {
// deprecated in protocol version 2026-07-28.
if protocolVersion >= protocolVersion20260728 {
return
}
c.mu.Lock()
@ -1592,8 +1592,8 @@ func (c *streamableServerConn) servePOST(w http.ResponseWriter, req *http.Reques
// SSE mode: write a priming event if supported.
//
// SEP-2575 removes Last-Event-ID-based resumable streams for protocol
// version >= 2026-06-30.
if c.eventStore != nil && effectiveVersion >= protocolVersion20251125 && effectiveVersion < protocolVersion20260630 {
// version >= 2026-07-28.
if c.eventStore != nil && effectiveVersion >= protocolVersion20251125 && effectiveVersion < protocolVersion20260728 {
// Write a priming event, as defined by [§2.1.6] of the spec.
//
// [§2.1.6]: https://modelcontextprotocol.io/specification/2025-11-25/basic/transports#sending-messages-to-the-server
@ -1754,7 +1754,7 @@ func (c *streamableServerConn) Write(ctx context.Context, msg jsonrpc.Message) e
delivered := false
var errs []error
protocolVersion := protocolVersionFromContext(ctx)
if c.eventStore != nil && protocolVersion < protocolVersion20260630 {
if c.eventStore != nil && protocolVersion < protocolVersion20260728 {
if err := c.eventStore.Append(ctx, c.sessionID, s.id, data); err != nil {
errs = append(errs, err)
} else {
@ -1765,12 +1765,12 @@ func (c *streamableServerConn) Write(ctx context.Context, msg jsonrpc.Message) e
// Compute eventID for SSE streams with event store.
// Use s.lastIdx + 1 because deliverLocked increments before writing.
var eventID string
if c.eventStore != nil && protocolVersion < protocolVersion20260630 {
if c.eventStore != nil && protocolVersion < protocolVersion20260728 {
eventID = formatEventID(s.id, s.lastIdx+1)
}
// SEP-2575: map protocol-level JSON-RPC error codes to HTTP status codes
// on the new protocol (>= 2026-06-30). When non-zero, deliverLocked will
// on the new protocol (>= 2026-07-28). When non-zero, deliverLocked will
// write the body as raw application/json with the override status.
overrideStatus := extractErrorStatus(ctx, msg)
@ -1974,10 +1974,10 @@ func (c *streamableClientConn) sessionUpdated(state clientSessionState) {
c.initializedResult = state.InitializeResult
c.mu.Unlock()
// Under SEP-2575 (protocol version >= 2026-06-30) the standalone HTTP GET
// Under SEP-2575 (protocol version >= 2026-07-28) the standalone HTTP GET
// SSE stream is removed.
if state.InitializeResult == nil ||
state.InitializeResult.ProtocolVersion >= protocolVersion20260630 {
state.InitializeResult.ProtocolVersion >= protocolVersion20260728 {
return
}

View file

@ -1234,7 +1234,7 @@ func TestStreamableClientOAuth_RetrieveError(t *testing.T) {
// discoverResult is the canned successful DiscoverResult returned by
// fakeStreamableServer setups in the tests below.
var discoverResult = &DiscoverResult{
SupportedVersions: []string{protocolVersion20260630},
SupportedVersions: []string{protocolVersion20260728},
Capabilities: &ServerCapabilities{
Tools: &ToolCapabilities{ListChanged: true},
},
@ -1244,7 +1244,7 @@ var discoverResult = &DiscoverResult{
// TestStreamableClientConnect_DiscoverSuccess verifies that Client.Connect on
// the streamable transport:
// - sends a POST server/discover with Mcp-Protocol-Version: 2026-06-30 and
// - sends a POST server/discover with Mcp-Protocol-Version: 2026-07-28 and
// the SEP-2575 per-request _meta triple in the body,
// - on a successful DiscoverResult, skips the legacy initialize handshake
// entirely, and
@ -1253,9 +1253,9 @@ var discoverResult = &DiscoverResult{
func TestStreamableClientConnect_DiscoverSuccess(t *testing.T) {
ctx := context.Background()
// Temporarily enable 2026-06-30 support in the SDK for this test
// Temporarily enable 2026-07-28 support in the SDK for this test
oldSupported := supportedProtocolVersions
supportedProtocolVersions = append([]string{protocolVersion20260630}, supportedProtocolVersions...)
supportedProtocolVersions = append([]string{protocolVersion20260728}, supportedProtocolVersions...)
t.Cleanup(func() {
supportedProtocolVersions = oldSupported
})
@ -1273,7 +1273,7 @@ func TestStreamableClientConnect_DiscoverSuccess(t *testing.T) {
"Content-Type": "application/json",
sessionIDHeader: "sess-1",
},
wantProtocolVersion: protocolVersion20260630,
wantProtocolVersion: protocolVersion20260728,
responseFunc: func(r *jsonrpc.Request) (string, int) {
gotDiscoverMu.Lock()
gotDiscover = r
@ -1290,7 +1290,7 @@ func TestStreamableClientConnect_DiscoverSuccess(t *testing.T) {
transport := &StreamableClientTransport{Endpoint: httpServer.URL}
client := NewClient(testImpl, nil)
session, err := client.Connect(ctx, transport, &ClientSessionOptions{protocolVersion: protocolVersion20260630})
session, err := client.Connect(ctx, transport, &ClientSessionOptions{protocolVersion: protocolVersion20260728})
if err != nil {
t.Fatalf("Connect: %v", err)
}
@ -1313,8 +1313,8 @@ func TestStreamableClientConnect_DiscoverSuccess(t *testing.T) {
if err := json.Unmarshal(gotDiscover.Params, &body); err != nil {
t.Fatalf("decoding discover params: %v", err)
}
if v, _ := body.Meta[MetaKeyProtocolVersion].(string); v != protocolVersion20260630 {
t.Errorf("_meta[%s] = %q, want %q", MetaKeyProtocolVersion, v, protocolVersion20260630)
if v, _ := body.Meta[MetaKeyProtocolVersion].(string); v != protocolVersion20260728 {
t.Errorf("_meta[%s] = %q, want %q", MetaKeyProtocolVersion, v, protocolVersion20260728)
}
if _, ok := body.Meta[MetaKeyClientInfo]; !ok {
t.Errorf("_meta[%s] missing", MetaKeyClientInfo)
@ -1327,7 +1327,7 @@ func TestStreamableClientConnect_DiscoverSuccess(t *testing.T) {
if ir == nil {
t.Fatal("InitializeResult is nil after Connect")
}
if got, want := ir.ProtocolVersion, protocolVersion20260630; got != want {
if got, want := ir.ProtocolVersion, protocolVersion20260728; got != want {
t.Errorf("InitializeResult.ProtocolVersion = %q, want %q", got, want)
}
if ir.ServerInfo == nil || ir.ServerInfo.Name != "discoverServer" {
@ -1363,7 +1363,7 @@ func TestStreamableClientConnect_DiscoverMethodNotFound(t *testing.T) {
responses: fakeResponses{
{"POST", "", methodDiscover, ""}: {
header: header{"Content-Type": "application/json"},
wantProtocolVersion: protocolVersion20260630,
wantProtocolVersion: protocolVersion20260728,
responseFunc: echoErr(&jsonrpc.Error{
Code: jsonrpc.CodeMethodNotFound,
Message: "method not found",
@ -1428,7 +1428,7 @@ func TestStreamableClientConnect_DiscoverUnsupportedVersion(t *testing.T) {
responses: fakeResponses{
{"POST", "", methodDiscover, ""}: {
header: header{"Content-Type": "application/json"},
wantProtocolVersion: protocolVersion20260630,
wantProtocolVersion: protocolVersion20260728,
responseFunc: echoErr(&jsonrpc.Error{
Code: CodeUnsupportedProtocolVersion,
Message: "unsupported protocol version",
@ -1486,7 +1486,7 @@ func TestStreamableClientConnect_DiscoverMethodNotFoundVPre(t *testing.T) {
t: t,
responses: fakeResponses{
{"POST", "", methodDiscover, ""}: {
wantProtocolVersion: protocolVersion20260630,
wantProtocolVersion: protocolVersion20260728,
// Reproduce the exact body a vPre server produces via
// http.Error(w, err.Error(), 400) where err comes from
// checkRequest. http.Error appends a trailing newline.
@ -1517,7 +1517,7 @@ func TestStreamableClientConnect_DiscoverMethodNotFoundVPre(t *testing.T) {
DisableStandaloneSSE: true,
}
client := NewClient(testImpl, nil)
session, err := client.Connect(ctx, transport, &ClientSessionOptions{protocolVersion: protocolVersion20260630})
session, err := client.Connect(ctx, transport, &ClientSessionOptions{protocolVersion: protocolVersion20260728})
if err != nil {
t.Fatalf("Connect: %v", err)
}
@ -1544,7 +1544,7 @@ func TestStreamableClientConnect_DiscoverUnsupportedVersionVPre(t *testing.T) {
t: t,
responses: fakeResponses{
{"POST", "", methodDiscover, ""}: {
wantProtocolVersion: protocolVersion20260630,
wantProtocolVersion: protocolVersion20260728,
body: "Bad Request: Unsupported protocol version\n",
status: http.StatusBadRequest,
header: header{"Content-Type": "text/plain; charset=utf-8"},
@ -1572,7 +1572,7 @@ func TestStreamableClientConnect_DiscoverUnsupportedVersionVPre(t *testing.T) {
DisableStandaloneSSE: true,
}
client := NewClient(testImpl, nil)
session, err := client.Connect(ctx, transport, &ClientSessionOptions{protocolVersion: protocolVersion20260630})
session, err := client.Connect(ctx, transport, &ClientSessionOptions{protocolVersion: protocolVersion20260728})
if err != nil {
t.Fatalf("Connect: %v", err)
}
@ -1591,7 +1591,7 @@ func TestStreamableClientConnect_DiscoverUnsupportedVersionNegotiation(t *testin
ctx := context.Background()
oldSupported := supportedProtocolVersions
supportedProtocolVersions = append([]string{protocolVersion20260630}, supportedProtocolVersions...)
supportedProtocolVersions = append([]string{protocolVersion20260728}, supportedProtocolVersions...)
t.Cleanup(func() {
supportedProtocolVersions = oldSupported
})
@ -1611,7 +1611,7 @@ func TestStreamableClientConnect_DiscoverUnsupportedVersionNegotiation(t *testin
n := discoverCalls.Add(1)
if n == 1 {
data, _ := json.Marshal(UnsupportedProtocolVersionData{
Supported: []string{protocolVersion20260630},
Supported: []string{protocolVersion20260728},
})
respMsg := &jsonrpc.Response{
ID: r.ID,
@ -1643,7 +1643,7 @@ func TestStreamableClientConnect_DiscoverUnsupportedVersionNegotiation(t *testin
if got, want := discoverCalls.Load(), int32(2); got != want {
t.Errorf("discover call count = %d, want %d", got, want)
}
if got := session.InitializeResult().ProtocolVersion; got != protocolVersion20260630 {
t.Errorf("InitializeResult.ProtocolVersion = %q, want %q", got, protocolVersion20260630)
if got := session.InitializeResult().ProtocolVersion; got != protocolVersion20260728 {
t.Errorf("InitializeResult.ProtocolVersion = %q, want %q", got, protocolVersion20260728)
}
}

View file

@ -27,7 +27,7 @@ const (
methodHeader = "Mcp-Method"
nameHeader = "Mcp-Name"
paramHeaderPrefix = "Mcp-Param-"
minVersionForStandardHeaders = protocolVersion20260630
minVersionForStandardHeaders = protocolVersion20260728
base64Prefix = "=?base64?"
base64Suffix = "?="
)

View file

@ -3223,7 +3223,7 @@ func TestStandaloneSSEEmitsCommentForHTTP2Flush(t *testing.T) {
}
// newProtocolBody builds a raw JSON body for a tools/call request that
// carries the >= 2026-06-30 per-request _meta fields.
// carries the >= 2026-07-28 per-request _meta fields.
func newProtocolBody(t *testing.T, toolName string, args any) []byte {
t.Helper()
rawArgs, err := json.Marshal(args)
@ -3236,7 +3236,7 @@ func newProtocolBody(t *testing.T, toolName string, args any) []byte {
"method": "tools/call",
"params": map[string]any{
"_meta": map[string]any{
MetaKeyProtocolVersion: protocolVersion20260630,
MetaKeyProtocolVersion: protocolVersion20260728,
MetaKeyClientInfo: map[string]any{"name": "new-proto-client", "version": "9.9"},
MetaKeyClientCapabilities: map[string]any{"sampling": map[string]any{}},
},
@ -3313,7 +3313,7 @@ func TestEphemeralConnectOpts(t *testing.T) {
req := mkReq(tt.body)
var pver string
if tt.wantUsesNew {
pver = protocolVersion20260630
pver = protocolVersion20260728
} else {
pver = protocolVersion20250326
}
@ -3351,10 +3351,10 @@ type statelessHandlerCapture struct {
func TestStreamableStateless_NewProtocolSession_NoFakeInit(t *testing.T) {
// SEP-2575: the MCP-Protocol-Version header is mandatory for new-protocol
// requests and must be a supported version. The 2026-06-30 version is
// requests and must be a supported version. The 2026-07-28 version is
// not yet in the global list, so register it for the duration of the test.
orig := supportedProtocolVersions
supportedProtocolVersions = append(slices.Clone(orig), protocolVersion20260630)
supportedProtocolVersions = append(slices.Clone(orig), protocolVersion20260728)
t.Cleanup(func() { supportedProtocolVersions = orig })
capture := &statelessHandlerCapture{}
@ -3384,8 +3384,8 @@ func TestStreamableStateless_NewProtocolSession_NoFakeInit(t *testing.T) {
}
httpReq.Header.Set("Content-Type", "application/json")
httpReq.Header.Set("Accept", "application/json, text/event-stream")
httpReq.Header.Set(protocolVersionHeader, protocolVersion20260630)
// >= 2026-06-30 also requires the Mcp-Method and Mcp-Name standard
httpReq.Header.Set(protocolVersionHeader, protocolVersion20260728)
// >= 2026-07-28 also requires the Mcp-Method and Mcp-Name standard
// headers (see streamable_headers.go).
httpReq.Header.Set(methodHeader, "tools/call")
httpReq.Header.Set(nameHeader, "capture")
@ -3405,14 +3405,14 @@ func TestStreamableStateless_NewProtocolSession_NoFakeInit(t *testing.T) {
if capture.sessionInitParams == nil {
t.Errorf("Session.InitializeParams() is nil, want populated initializeParams for new-protocol session")
} else {
if got, want := capture.sessionInitParams.ProtocolVersion, protocolVersion20260630; got != want {
if got, want := capture.sessionInitParams.ProtocolVersion, protocolVersion20260728; got != want {
t.Errorf("Session.InitializeParams().ProtocolVersion = %q, want %q", got, want)
}
if got, want := capture.sessionInitParams.ClientInfo.Name, "new-proto-client"; got != want {
t.Errorf("Session.InitializeParams().ClientInfo.Name = %q, want %q", got, want)
}
}
if got, want := capture.reqProtocolVersion, protocolVersion20260630; got != want {
if got, want := capture.reqProtocolVersion, protocolVersion20260728; got != want {
t.Errorf("req.ProtocolVersion() = %q, want %q", got, want)
}
if capture.reqClientInfo == nil || capture.reqClientInfo.Name != "new-proto-client" {
@ -3424,14 +3424,14 @@ func TestStreamableStateless_NewProtocolSession_NoFakeInit(t *testing.T) {
}
// TestStreamableStateful_RejectsNewProtocol verifies that a stateful HTTP
// server rejects requests carrying _meta.protocolVersion (i.e. >= 2026-06-30
// server rejects requests carrying _meta.protocolVersion (i.e. >= 2026-07-28
// requests) with HTTP 400. The new protocol is
// supported on HTTP only when StreamableHTTPOptions.Stateless=true.
func TestStreamableStateful_RejectsNewProtocol(t *testing.T) {
// Make 2026-06-30 a "known" version so that the request reaches servePOST
// Make 2026-07-28 a "known" version so that the request reaches servePOST
// (otherwise the early header validation at ServeHTTP rejects it).
orig := supportedProtocolVersions
supportedProtocolVersions = append(slices.Clone(orig), protocolVersion20260630)
supportedProtocolVersions = append(slices.Clone(orig), protocolVersion20260728)
t.Cleanup(func() { supportedProtocolVersions = orig })
server := NewServer(testImpl, nil)
@ -3472,7 +3472,7 @@ func TestStreamableStateful_RejectsNewProtocol(t *testing.T) {
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Accept", "application/json, text/event-stream")
req.Header.Set(sessionIDHeader, sessionID)
req.Header.Set(protocolVersionHeader, protocolVersion20260630)
req.Header.Set(protocolVersionHeader, protocolVersion20260728)
req.Header.Set(methodHeader, "tools/call")
req.Header.Set(nameHeader, "noop")
@ -3496,7 +3496,7 @@ func TestStreamableStateful_RejectsNewProtocol(t *testing.T) {
// fire on Stateless: true).
func TestStreamableStateless_AcceptsNewProtocol(t *testing.T) {
orig := supportedProtocolVersions
supportedProtocolVersions = append(slices.Clone(orig), protocolVersion20260630)
supportedProtocolVersions = append(slices.Clone(orig), protocolVersion20260728)
t.Cleanup(func() { supportedProtocolVersions = orig })
server := NewServer(testImpl, nil)
@ -3518,7 +3518,7 @@ func TestStreamableStateless_AcceptsNewProtocol(t *testing.T) {
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Accept", "application/json, text/event-stream")
req.Header.Set(protocolVersionHeader, protocolVersion20260630)
req.Header.Set(protocolVersionHeader, protocolVersion20260728)
req.Header.Set(methodHeader, "tools/call")
req.Header.Set(nameHeader, "noop")
@ -3534,7 +3534,7 @@ func TestStreamableStateless_AcceptsNewProtocol(t *testing.T) {
}
// TestStreamableClientUnsupportedVersionFallback exercises the full
// SEP-2575 fallback. The client requests protocolVersion20260630, which the server does
// SEP-2575 fallback. The client requests protocolVersion20260728, which the server does
// not advertise in supportedProtocolVersions. The server therefore rejects
// the server/discover POST at the transport-level header validation with a
// plain HTTP 400 ("Bad Request: Unsupported protocol version ..."). The
@ -3556,7 +3556,7 @@ func TestStreamableClientUnsupportedVersionFallback(t *testing.T) {
client := NewClient(testImpl, nil)
transport := &StreamableClientTransport{Endpoint: httpServer.URL}
session, err := client.Connect(ctx, transport, &ClientSessionOptions{protocolVersion: protocolVersion20260630})
session, err := client.Connect(ctx, transport, &ClientSessionOptions{protocolVersion: protocolVersion20260728})
if err != nil {
t.Fatalf("Connect: %v", err)
}
@ -3579,14 +3579,14 @@ func TestStreamableClientUnsupportedVersionFallback(t *testing.T) {
}
// TestStreamableStateful_AcceptsDiscover verifies that a stateful HTTP server
// accepts a server/discover probe carrying MCP-Protocol-Version: 2026-06-30
// accepts a server/discover probe carrying MCP-Protocol-Version: 2026-07-28
// (and the matching _meta.protocolVersion), instead of rejecting it with the
// "stateless required" 400. The SEP-2575 client flow has the client probing
// the server with the new protocol version to learn which versions are
// supported.
func TestStreamableStateful_AcceptsDiscover(t *testing.T) {
orig := supportedProtocolVersions
supportedProtocolVersions = append(slices.Clone(orig), protocolVersion20260630)
supportedProtocolVersions = append(slices.Clone(orig), protocolVersion20260728)
t.Cleanup(func() { supportedProtocolVersions = orig })
server := NewServer(testImpl, nil)
@ -3600,7 +3600,7 @@ func TestStreamableStateful_AcceptsDiscover(t *testing.T) {
"method": methodDiscover,
"params": map[string]any{
"_meta": map[string]any{
MetaKeyProtocolVersion: protocolVersion20260630,
MetaKeyProtocolVersion: protocolVersion20260728,
MetaKeyClientInfo: map[string]any{"name": "new-proto-client", "version": "9.9"},
MetaKeyClientCapabilities: map[string]any{"sampling": map[string]any{}},
},
@ -3615,7 +3615,7 @@ func TestStreamableStateful_AcceptsDiscover(t *testing.T) {
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Accept", "application/json, text/event-stream")
req.Header.Set(protocolVersionHeader, protocolVersion20260630)
req.Header.Set(protocolVersionHeader, protocolVersion20260728)
req.Header.Set(methodHeader, methodDiscover)
resp, err := http.DefaultClient.Do(req)
@ -3651,9 +3651,9 @@ func TestStreamableStateful_AcceptsDiscover(t *testing.T) {
if rpcResp.Result == nil {
t.Fatalf("discover returned no result; body = %s", respBody)
}
if slices.Contains(rpcResp.Result.SupportedVersions, protocolVersion20260630) {
if slices.Contains(rpcResp.Result.SupportedVersions, protocolVersion20260728) {
t.Errorf("DiscoverResult.SupportedVersions = %v, must not include %q on a stateful transport",
rpcResp.Result.SupportedVersions, protocolVersion20260630)
rpcResp.Result.SupportedVersions, protocolVersion20260728)
}
if len(rpcResp.Result.SupportedVersions) == 0 {
t.Errorf("DiscoverResult.SupportedVersions is empty; want at least one legacy version")
@ -3665,7 +3665,7 @@ func TestStreamableStateful_AcceptsDiscover(t *testing.T) {
func TestStreamableHTTP_E2E_DiscoverSuccess(t *testing.T) {
ctx := context.Background()
orig := supportedProtocolVersions
supportedProtocolVersions = append([]string{protocolVersion20260630}, slices.Clone(orig)...)
supportedProtocolVersions = append([]string{protocolVersion20260728}, slices.Clone(orig)...)
t.Cleanup(func() { supportedProtocolVersions = orig })
server := NewServer(&Implementation{Name: "e2e-server", Version: "v1"}, nil)
@ -3689,7 +3689,7 @@ func TestStreamableHTTP_E2E_DiscoverSuccess(t *testing.T) {
client := NewClient(&Implementation{Name: "e2e-client", Version: "v1"}, nil)
transport := &StreamableClientTransport{Endpoint: httpServer.URL}
cs, err := client.Connect(ctx, transport, &ClientSessionOptions{protocolVersion: protocolVersion20260630})
cs, err := client.Connect(ctx, transport, &ClientSessionOptions{protocolVersion: protocolVersion20260728})
if err != nil {
t.Fatalf("Connect: %v", err)
}
@ -3699,9 +3699,9 @@ func TestStreamableHTTP_E2E_DiscoverSuccess(t *testing.T) {
if ir == nil {
t.Fatal("InitializeResult is nil after Connect; discover should have populated it")
}
if ir.ProtocolVersion != protocolVersion20260630 {
if ir.ProtocolVersion != protocolVersion20260728 {
t.Errorf("InitializeResult.ProtocolVersion = %q, want %q (negotiated via discover)",
ir.ProtocolVersion, protocolVersion20260630)
ir.ProtocolVersion, protocolVersion20260728)
}
if ir.ServerInfo == nil || ir.ServerInfo.Name != "e2e-server" {
t.Errorf("InitializeResult.ServerInfo = %+v, want name=e2e-server", ir.ServerInfo)