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 non-zero, defines an interval for regular "ping" requests.
// If the peer fails to respond to pings originating from the keepalive check, // If the peer fails to respond to pings originating from the keepalive check,
// the session is automatically closed. // 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 KeepAlive time.Duration
// KeepAliveFailureThreshold is the number of consecutive keepalive ping // KeepAliveFailureThreshold is the number of consecutive keepalive ping
// failures tolerated before the session is closed. A value of 0 or 1 // 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 protocolVersion = opts.protocolVersion
} }
if protocolVersion >= protocolVersion20260630 { if protocolVersion >= protocolVersion20260728 {
// Per SEP-2575, try the stateless server/discover RPC first. If the server // 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 // signals it doesn't support it, fall back to the legacy initialize
// handshake. // 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 { if errors.As(err, &werr) && werr.Code == CodeUnsupportedProtocolVersion && werr.Data != nil {
var data UnsupportedProtocolVersionData var data UnsupportedProtocolVersionData
if err := json.Unmarshal(werr.Data, &data); err == nil { 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) discoverCtx = context.WithValue(ctx, protocolVersionContextKey{}, negotiatedVersion)
continue continue
} }
@ -381,7 +381,7 @@ func (c *Client) discover(ctx context.Context, cs *ClientSession) (*InitializeRe
} else { } else {
negotiated = negotiateMutuallySupportedVersion(res.SupportedVersions) negotiated = negotiateMutuallySupportedVersion(res.SupportedVersions)
} }
if negotiated == "" || negotiated < protocolVersion20260630 { if negotiated == "" || negotiated < protocolVersion20260728 {
// If there is no overlap, fall back to initialize so version // If there is no overlap, fall back to initialize so version
// negotiation can happen via the legacy path. // negotiation can happen via the legacy path.
return nil, jsonrpc2.ErrUnsupportedProtocolVersion return nil, jsonrpc2.ErrUnsupportedProtocolVersion
@ -436,11 +436,11 @@ type clientSessionState struct {
func (cs *ClientSession) InitializeResult() *InitializeResult { return cs.state.InitializeResult } func (cs *ClientSession) InitializeResult() *InitializeResult { return cs.state.InitializeResult }
// usesNewProtocol reports whether this session has negotiated a protocol // 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. // triple on every outgoing request.
func (cs *ClientSession) usesNewProtocol() bool { func (cs *ClientSession) usesNewProtocol() bool {
res := cs.state.InitializeResult 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 // 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 // don't overlap with the SDK. The test then asserts the resulting session
// state and whether the legacy initialize handshake ran. // state and whether the legacy initialize handshake ran.
func TestClientConnectDiscover(t *testing.T) { 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 oldSupported := supportedProtocolVersions
supportedProtocolVersions = append([]string{protocolVersion20260630}, supportedProtocolVersions...) supportedProtocolVersions = append([]string{protocolVersion20260728}, supportedProtocolVersions...)
t.Cleanup(func() { t.Cleanup(func() {
supportedProtocolVersions = oldSupported supportedProtocolVersions = oldSupported
}) })
@ -668,7 +668,7 @@ func TestClientConnectDiscover(t *testing.T) {
name: "discover success skips initialize", name: "discover success skips initialize",
discoverHandler: func() (Result, error) { discoverHandler: func() (Result, error) {
return &DiscoverResult{ return &DiscoverResult{
SupportedVersions: []string{protocolVersion20260630}, SupportedVersions: []string{protocolVersion20260728},
Capabilities: &ServerCapabilities{ Capabilities: &ServerCapabilities{
Tools: &ToolCapabilities{ListChanged: true}, Tools: &ToolCapabilities{ListChanged: true},
}, },
@ -676,7 +676,7 @@ func TestClientConnectDiscover(t *testing.T) {
}, nil }, nil
}, },
wantInitialize: false, wantInitialize: false,
wantVersion: protocolVersion20260630, wantVersion: protocolVersion20260728,
}, },
{ {
name: "method not found falls back to initialize", name: "method not found falls back to initialize",
@ -742,7 +742,7 @@ func TestClientConnectDiscover(t *testing.T) {
defer ss.Close() defer ss.Close()
c := NewClient(testImpl, nil) 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 { if err != nil {
t.Fatalf("Connect: %v", err) t.Fatalf("Connect: %v", err)
} }
@ -770,7 +770,7 @@ func TestClientConnectDiscover(t *testing.T) {
// protocolVersion, clientInfo, and clientCapabilities. // protocolVersion, clientInfo, and clientCapabilities.
func TestClientConnectDiscover_RequestContents(t *testing.T) { func TestClientConnectDiscover_RequestContents(t *testing.T) {
orig := supportedProtocolVersions orig := supportedProtocolVersions
supportedProtocolVersions = append([]string{protocolVersion20260630}, slices.Clone(orig)...) supportedProtocolVersions = append([]string{protocolVersion20260728}, slices.Clone(orig)...)
t.Cleanup(func() { supportedProtocolVersions = orig }) t.Cleanup(func() { supportedProtocolVersions = orig })
ctx := context.Background() ctx := context.Background()
@ -811,7 +811,7 @@ func TestClientConnectDiscover_RequestContents(t *testing.T) {
return nil, nil return nil, nil
}, },
}) })
cs, err := c.Connect(ctx, ct, &ClientSessionOptions{protocolVersion: protocolVersion20260630}) cs, err := c.Connect(ctx, ct, &ClientSessionOptions{protocolVersion: protocolVersion20260728})
if err != nil { if err != nil {
t.Fatalf("Connect: %v", err) t.Fatalf("Connect: %v", err)
} }
@ -822,8 +822,8 @@ func TestClientConnectDiscover_RequestContents(t *testing.T) {
} }
meta := got.params.GetMeta() meta := got.params.GetMeta()
if v, _ := meta[MetaKeyProtocolVersion].(string); v != protocolVersion20260630 { if v, _ := meta[MetaKeyProtocolVersion].(string); v != protocolVersion20260728 {
t.Errorf("_meta[%s] = %q, want %q", MetaKeyProtocolVersion, v, protocolVersion20260630) t.Errorf("_meta[%s] = %q, want %q", MetaKeyProtocolVersion, v, protocolVersion20260728)
} }
// _meta values round-trip through JSON, so on the server side they // _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. // 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() ctx := context.Background()
orig := supportedProtocolVersions orig := supportedProtocolVersions
supportedProtocolVersions = append([]string{protocolVersion20260630}, slices.Clone(orig)...) supportedProtocolVersions = append([]string{protocolVersion20260728}, slices.Clone(orig)...)
t.Cleanup(func() { supportedProtocolVersions = orig }) t.Cleanup(func() { supportedProtocolVersions = orig })
server := NewServer(&Implementation{Name: "stdio-like-server", Version: "v1"}, nil) server := NewServer(&Implementation{Name: "stdio-like-server", Version: "v1"}, nil)
@ -861,7 +861,7 @@ func TestInMemory_E2E_DiscoverSuccess(t *testing.T) {
defer ss.Close() defer ss.Close()
client := NewClient(&Implementation{Name: "stdio-like-client", Version: "v1"}, nil) 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 { if err != nil {
t.Fatalf("client.Connect: %v", err) t.Fatalf("client.Connect: %v", err)
} }
@ -871,9 +871,9 @@ func TestInMemory_E2E_DiscoverSuccess(t *testing.T) {
if ir == nil { if ir == nil {
t.Fatal("InitializeResult is nil; discover should have populated it") 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)", 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" { if ir.ServerInfo == nil || ir.ServerInfo.Name != "stdio-like-server" {
t.Errorf("InitializeResult.ServerInfo = %+v, want name=stdio-like-server", ir.ServerInfo) 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 // TestInMemory_E2E_DiscoverFallback_NoOverlap verifies the fallback path
// over an InMemory (STDIO-equivalent) transport: the client probes with // 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 // NOT include that version (the default for an SDK server that hasn't
// shimmed supportedProtocolVersions). // shimmed supportedProtocolVersions).
func TestInMemory_E2E_DiscoverFallback_NoOverlap(t *testing.T) { func TestInMemory_E2E_DiscoverFallback_NoOverlap(t *testing.T) {
ctx := context.Background() ctx := context.Background()
orig := supportedProtocolVersions orig := supportedProtocolVersions
supportedProtocolVersions = append([]string{protocolVersion20260630}, slices.Clone(orig)...) supportedProtocolVersions = append([]string{protocolVersion20260728}, slices.Clone(orig)...)
t.Cleanup(func() { supportedProtocolVersions = orig }) t.Cleanup(func() { supportedProtocolVersions = orig })
server := NewServer(&Implementation{Name: "vpre-like-server", Version: "v1"}, nil) 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() defer ss.Close()
client := NewClient(&Implementation{Name: "new-client", Version: "v1"}, nil) 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 { if err != nil {
t.Fatalf("client.Connect: %v", err) t.Fatalf("client.Connect: %v", err)
} }
@ -948,7 +948,7 @@ func TestInMemory_E2E_DiscoverFallback_MethodNotFound(t *testing.T) {
ctx := context.Background() ctx := context.Background()
orig := supportedProtocolVersions orig := supportedProtocolVersions
supportedProtocolVersions = append([]string{protocolVersion20260630}, slices.Clone(orig)...) supportedProtocolVersions = append([]string{protocolVersion20260728}, slices.Clone(orig)...)
t.Cleanup(func() { supportedProtocolVersions = orig }) t.Cleanup(func() { supportedProtocolVersions = orig })
server := NewServer(&Implementation{Name: "vpre-server", Version: "v1"}, nil) server := NewServer(&Implementation{Name: "vpre-server", Version: "v1"}, nil)
@ -969,7 +969,7 @@ func TestInMemory_E2E_DiscoverFallback_MethodNotFound(t *testing.T) {
defer ss.Close() defer ss.Close()
client := NewClient(&Implementation{Name: "new-client", Version: "v1"}, nil) 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 { if err != nil {
t.Fatalf("client.Connect: %v", err) t.Fatalf("client.Connect: %v", err)
} }
@ -997,7 +997,7 @@ func TestInMemory_E2E_DiscoverFallback_UnsupportedProtocolVersion(t *testing.T)
ctx := context.Background() ctx := context.Background()
orig := supportedProtocolVersions orig := supportedProtocolVersions
supportedProtocolVersions = append([]string{protocolVersion20260630}, slices.Clone(orig)...) supportedProtocolVersions = append([]string{protocolVersion20260728}, slices.Clone(orig)...)
t.Cleanup(func() { supportedProtocolVersions = orig }) t.Cleanup(func() { supportedProtocolVersions = orig })
server := NewServer(&Implementation{Name: "strict-server", Version: "v1"}, nil) server := NewServer(&Implementation{Name: "strict-server", Version: "v1"}, nil)
@ -1021,7 +1021,7 @@ func TestInMemory_E2E_DiscoverFallback_UnsupportedProtocolVersion(t *testing.T)
defer ss.Close() defer ss.Close()
client := NewClient(&Implementation{Name: "new-client", Version: "v1"}, nil) 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 { if err != nil {
t.Fatalf("client.Connect: %v", err) 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. // selects a mutually supported version from that list and retries.
func TestClientConnectDiscover_UnsupportedVersionNegotiation(t *testing.T) { func TestClientConnectDiscover_UnsupportedVersionNegotiation(t *testing.T) {
oldSupported := supportedProtocolVersions oldSupported := supportedProtocolVersions
supportedProtocolVersions = append([]string{protocolVersion20260630}, slices.Clone(oldSupported)...) supportedProtocolVersions = append([]string{protocolVersion20260728}, slices.Clone(oldSupported)...)
t.Cleanup(func() { supportedProtocolVersions = oldSupported }) t.Cleanup(func() { supportedProtocolVersions = oldSupported })
ctx := context.Background() ctx := context.Background()
@ -1095,8 +1095,8 @@ func TestClientConnectDiscover_UnsupportedVersionNegotiation(t *testing.T) {
if got, want := discoverCalls.Load(), int32(1); got != want { 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) 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 { if got, _ := observedDiscoverVersion.Load().(string); got != protocolVersion20260728 {
t.Errorf("retry discover requested version = %q, want %q (highest mutually supported version)", got, protocolVersion20260630) t.Errorf("retry discover requested version = %q, want %q (highest mutually supported version)", got, protocolVersion20260728)
} }
if gotInitialize.Load() { if gotInitialize.Load() {
t.Error("legacy initialize handshake ran, but negotiated discover should have succeeded") 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 { if ir == nil {
t.Fatal("InitializeResult is nil after Connect") 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) 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 { if iparams := ss.InitializeParams(); iparams != nil {
protocolVersion = iparams.ProtocolVersion protocolVersion = iparams.ProtocolVersion
} }
return protocolVersion >= protocolVersion20260630 return protocolVersion >= protocolVersion20260728
} }
func clientMultiRoundTripMiddleware() Middleware { func clientMultiRoundTripMiddleware() Middleware {

View file

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

View file

@ -2138,7 +2138,7 @@ const (
methodUnsubscribe = "resources/unsubscribe" 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 // These keys appear inside a Params._meta map and carry information that
// previously came from the initialization handshake (SEP-2575). // 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 // logLevelContextKey carries the per-request log level from
// [ServerSession.handle] to [ServerSession.Log] for new-protocol // [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 — // — including handler goroutines that call [ServerSession.Log] concurrently —
// rather than to the session, which avoids races between concurrent requests // 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 // 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. // 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 // originating request's `_meta` field (SEP-2575); an absent or empty value
// suppresses the message per spec. For old-protocol requests, the level is // suppresses the message per spec. For old-protocol requests, the level is
// taken from the session state set via `logging/setLevel`. // 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: case methodDiscover:
// In case of methodDiscover call the state.initializeParams is populated // In case of methodDiscover call the state.initializeParams is populated
// within the discover handle function to make sure the method is supported // 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: default:
if !initialized && !validatedMeta.usesNewProtocol { if !initialized && !validatedMeta.usesNewProtocol {
ss.server.opts.Logger.Error("method invalid during initialization", "method", req.Method) 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). // rejected with `Method not found` (-32601).
func TestServerSessionHandle_RejectsInitializeOnNewProtocol(t *testing.T) { func TestServerSessionHandle_RejectsInitializeOnNewProtocol(t *testing.T) {
orig := supportedProtocolVersions orig := supportedProtocolVersions
supportedProtocolVersions = append([]string{protocolVersion20260630}, slices.Clone(orig)...) supportedProtocolVersions = append([]string{protocolVersion20260728}, slices.Clone(orig)...)
t.Cleanup(func() { supportedProtocolVersions = orig }) t.Cleanup(func() { supportedProtocolVersions = orig })
tests := []struct { tests := []struct {
@ -1303,11 +1303,11 @@ func TestServerSessionHandle_RejectsInitializeOnNewProtocol(t *testing.T) {
name: "initialize with new-protocol _meta is rejected", name: "initialize with new-protocol _meta is rejected",
params: map[string]any{ params: map[string]any{
"_meta": map[string]any{ "_meta": map[string]any{
MetaKeyProtocolVersion: protocolVersion20260630, MetaKeyProtocolVersion: protocolVersion20260728,
MetaKeyClientInfo: map[string]any{"name": "c", "version": "1"}, MetaKeyClientInfo: map[string]any{"name": "c", "version": "1"},
MetaKeyClientCapabilities: map[string]any{}, MetaKeyClientCapabilities: map[string]any{},
}, },
"protocolVersion": protocolVersion20260630, "protocolVersion": protocolVersion20260728,
}, },
wantReject: true, wantReject: true,
}, },
@ -1372,11 +1372,11 @@ func TestServerSessionHandle_RejectsInitializeOnNewProtocol(t *testing.T) {
Method: methodInitialize, Method: methodInitialize,
Params: mustMarshal(map[string]any{ Params: mustMarshal(map[string]any{
"_meta": map[string]any{ "_meta": map[string]any{
MetaKeyProtocolVersion: protocolVersion20260630, MetaKeyProtocolVersion: protocolVersion20260728,
MetaKeyClientInfo: map[string]any{"name": "c", "version": "1"}, MetaKeyClientInfo: map[string]any{"name": "c", "version": "1"},
MetaKeyClientCapabilities: map[string]any{}, MetaKeyClientCapabilities: map[string]any{},
}, },
"protocolVersion": protocolVersion20260630, "protocolVersion": protocolVersion20260728,
}), }),
} }
_, handleErr := ss.handle(context.Background(), req) _, handleErr := ss.handle(context.Background(), req)
@ -1408,12 +1408,12 @@ func TestServerSessionHandle_RejectsInitializeOnNewProtocol(t *testing.T) {
// protocol via `_meta.protocolVersion`. // protocol via `_meta.protocolVersion`.
func TestServerSessionHandle_RejectsRemovedMethodsOnNewProtocol(t *testing.T) { func TestServerSessionHandle_RejectsRemovedMethodsOnNewProtocol(t *testing.T) {
orig := supportedProtocolVersions orig := supportedProtocolVersions
supportedProtocolVersions = append([]string{protocolVersion20260630}, slices.Clone(orig)...) supportedProtocolVersions = append([]string{protocolVersion20260728}, slices.Clone(orig)...)
t.Cleanup(func() { supportedProtocolVersions = orig }) t.Cleanup(func() { supportedProtocolVersions = orig })
newProtoMeta := map[string]any{ newProtoMeta := map[string]any{
"_meta": map[string]any{ "_meta": map[string]any{
MetaKeyProtocolVersion: protocolVersion20260630, MetaKeyProtocolVersion: protocolVersion20260728,
MetaKeyClientInfo: map[string]any{"name": "c", "version": "1"}, MetaKeyClientInfo: map[string]any{"name": "c", "version": "1"},
MetaKeyClientCapabilities: map[string]any{}, MetaKeyClientCapabilities: map[string]any{},
}, },

View file

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

View file

@ -50,7 +50,7 @@ func TestValidateRequestMeta(t *testing.T) {
method: methodCallTool, method: methodCallTool,
params: map[string]any{ params: map[string]any{
"_meta": map[string]any{ "_meta": map[string]any{
MetaKeyProtocolVersion: protocolVersion20260630, MetaKeyProtocolVersion: protocolVersion20260728,
MetaKeyClientInfo: map[string]any{"name": "c", "version": "1"}, MetaKeyClientInfo: map[string]any{"name": "c", "version": "1"},
MetaKeyClientCapabilities: map[string]any{}, MetaKeyClientCapabilities: map[string]any{},
}, },
@ -63,7 +63,7 @@ func TestValidateRequestMeta(t *testing.T) {
method: methodCallTool, method: methodCallTool,
params: map[string]any{ params: map[string]any{
"_meta": map[string]any{ "_meta": map[string]any{
MetaKeyProtocolVersion: protocolVersion20260630, MetaKeyProtocolVersion: protocolVersion20260728,
MetaKeyClientCapabilities: map[string]any{}, MetaKeyClientCapabilities: map[string]any{},
}, },
"name": "x", "name": "x",
@ -76,7 +76,7 @@ func TestValidateRequestMeta(t *testing.T) {
method: methodCallTool, method: methodCallTool,
params: map[string]any{ params: map[string]any{
"_meta": map[string]any{ "_meta": map[string]any{
MetaKeyProtocolVersion: protocolVersion20260630, MetaKeyProtocolVersion: protocolVersion20260728,
MetaKeyClientInfo: map[string]any{"name": "c", "version": "1"}, MetaKeyClientInfo: map[string]any{"name": "c", "version": "1"},
}, },
"name": "x", "name": "x",
@ -90,7 +90,7 @@ func TestValidateRequestMeta(t *testing.T) {
isNotification: true, isNotification: true,
params: map[string]any{ params: map[string]any{
"_meta": map[string]any{ "_meta": map[string]any{
MetaKeyProtocolVersion: protocolVersion20260630, MetaKeyProtocolVersion: protocolVersion20260728,
}, },
"requestId": "r1", "requestId": "r1",
}, },
@ -107,7 +107,7 @@ func TestValidateRequestMeta(t *testing.T) {
method: methodCallTool, method: methodCallTool,
params: map[string]any{ params: map[string]any{
"_meta": map[string]any{ "_meta": map[string]any{
MetaKeyProtocolVersion: protocolVersion20260630, MetaKeyProtocolVersion: protocolVersion20260728,
MetaKeyClientInfo: map[string]any{"name": "c", "version": "1"}, MetaKeyClientInfo: map[string]any{"name": "c", "version": "1"},
MetaKeyClientCapabilities: map[string]any{}, MetaKeyClientCapabilities: map[string]any{},
MetaKeyLogLevel: "warning", MetaKeyLogLevel: "warning",
@ -122,7 +122,7 @@ func TestValidateRequestMeta(t *testing.T) {
method: methodCallTool, method: methodCallTool,
params: map[string]any{ params: map[string]any{
"_meta": map[string]any{ "_meta": map[string]any{
MetaKeyProtocolVersion: protocolVersion20260630, MetaKeyProtocolVersion: protocolVersion20260728,
MetaKeyClientInfo: map[string]any{"name": "c", "version": "1"}, MetaKeyClientInfo: map[string]any{"name": "c", "version": "1"},
MetaKeyClientCapabilities: map[string]any{}, MetaKeyClientCapabilities: map[string]any{},
}, },
@ -190,15 +190,15 @@ func TestServerRequest_PerRequestAccessors(t *testing.T) {
info := &Implementation{Name: "c", Version: "1"} info := &Implementation{Name: "c", Version: "1"}
params := &CallToolParamsRaw{ params := &CallToolParamsRaw{
Meta: Meta{ Meta: Meta{
MetaKeyProtocolVersion: protocolVersion20260630, MetaKeyProtocolVersion: protocolVersion20260728,
MetaKeyClientInfo: info, MetaKeyClientInfo: info,
MetaKeyClientCapabilities: caps, MetaKeyClientCapabilities: caps,
}, },
Name: "x", Name: "x",
} }
req := &ServerRequest[*CallToolParamsRaw]{Params: params} req := &ServerRequest[*CallToolParamsRaw]{Params: params}
if got := req.ProtocolVersion(); got != protocolVersion20260630 { if got := req.ProtocolVersion(); got != protocolVersion20260728 {
t.Errorf("ProtocolVersion = %q, want %q", got, protocolVersion20260630) t.Errorf("ProtocolVersion = %q, want %q", got, protocolVersion20260728)
} }
if got := req.ClientInfo(); got == nil || got.Name != "c" { if got := req.ClientInfo(); got == nil || got.Name != "c" {
t.Errorf("ClientInfo = %+v, want Name=c", got) 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. // re-decode them into typed Go values.
raw := json.RawMessage(`{ raw := json.RawMessage(`{
"_meta": { "_meta": {
"io.modelcontextprotocol/protocolVersion": "2026-06-30", "io.modelcontextprotocol/protocolVersion": "2026-07-28",
"io.modelcontextprotocol/clientInfo": {"name": "wire-client", "version": "9"}, "io.modelcontextprotocol/clientInfo": {"name": "wire-client", "version": "9"},
"io.modelcontextprotocol/clientCapabilities": {"sampling": {}} "io.modelcontextprotocol/clientCapabilities": {"sampling": {}}
}, },
@ -224,7 +224,7 @@ func TestServerRequest_PerRequestAccessors_FromJSON(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
req := &ServerRequest[*CallToolParamsRaw]{Params: &params} 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) t.Errorf("ProtocolVersion = %q, want %q", got, want)
} }
gotInfo := req.ClientInfo() 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 // [§2.7]: https://modelcontextprotocol.io/specification/2025-06-18/basic/transports#protocol-version-header
protocolVersion := req.Header.Get(protocolVersionHeader) 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) http.Error(w, fmt.Sprintf("Bad Request: Unsupported protocol version (supported versions: %s)", strings.Join(supportedProtocolVersions, ",")), http.StatusBadRequest)
return return
} }
@ -414,7 +414,7 @@ func (h *StreamableHTTPHandler) serveStatelessLegacyDELETE(w http.ResponseWriter
// ephemeralConnectOpts peeks at the request body to determine whether it // ephemeralConnectOpts peeks at the request body to determine whether it
// contains an initialize or initialized message or whether the protocol version // 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 // For old-protocol requests, default session state is synthesized so that
// the session's init gate doesn't reject the request. // 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. // It is used for both stateless servers and stateful servers with no session ID.
// //
// The returned usesNewProtocol bool reports whether the protocol version // 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) { func (h *StreamableHTTPHandler) ephemeralConnectOpts(req *http.Request) (opts *ServerSessionOptions, usesNewProtocol bool, err error) {
protocolVersion := protocolVersionFromContext(req.Context()) protocolVersion := protocolVersionFromContext(req.Context())
if protocolVersion == "" { if protocolVersion == "" {
@ -446,7 +446,7 @@ func (h *StreamableHTTPHandler) ephemeralConnectOpts(req *http.Request) (opts *S
case notificationInitialized: case notificationInitialized:
hasInitialized = true hasInitialized = true
} }
if protocolVersion >= protocolVersion20260630 { if protocolVersion >= protocolVersion20260728 {
usesNewProtocol = true 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, // 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. // transport is configured as stateless.
func (t *StreamableServerTransport) SupportsProtocolVersion(version string) bool { func (t *StreamableServerTransport) SupportsProtocolVersion(version string) bool {
if version >= protocolVersion20260630 { if version >= protocolVersion20260728 {
return t.Stateless && slices.Contains(supportedProtocolVersions, version) return t.Stateless && slices.Contains(supportedProtocolVersions, version)
} }
return 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 // extractErrorStatus reports the HTTP status to send when the given
// outgoing message is a JSON-RPC error response under the SEP-2575 protocol // outgoing message is a JSON-RPC error response under the SEP-2575 protocol
// (>= 2026-06-30). // (>= 2026-07-28).
// //
// Per SEP-2575: // Per SEP-2575:
// - MethodNotFound (-32601) MUST return HTTP 404. // - MethodNotFound (-32601) MUST return HTTP 404.
// - InvalidParams (-32602) and UnsupportedProtocolVersion (-32004) MUST // - InvalidParams (-32602) and UnsupportedProtocolVersion (-32004) MUST
// return HTTP 400. // return HTTP 400.
func extractErrorStatus(ctx context.Context, msg jsonrpc.Message) int { func extractErrorStatus(ctx context.Context, msg jsonrpc.Message) int {
if protocolVersionFromContext(ctx) < protocolVersion20260630 { if protocolVersionFromContext(ctx) < protocolVersion20260728 {
return 0 return 0
} }
resp, ok := msg.(*jsonrpc.Response) 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. // 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 // 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 // response body with Content-Type: application/json and HTTP status
// overrideStatus. // 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) { 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 { if err := c.eventStore.Open(ctx, c.sessionID, id); err != nil {
return nil, err 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 // the HTTP request. If we didn't do this, a request with a bad method or
// missing ID could be silently swallowed. // missing ID could be silently swallowed.
if _, err := checkRequest(jreq, serverMethodInfos); err != nil { 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{ writeJSONRPCError(w, http.StatusNotFound, jreq.ID, &jsonrpc.Error{
Code: jsonrpc.CodeMethodNotFound, Code: jsonrpc.CodeMethodNotFound,
Message: err.Error(), 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 // SEP-2575: requests carrying `_meta.protocolVersion` require the
// Mcp-Protocol-Version HTTP header to be present and to match the // Mcp-Protocol-Version HTTP header to be present and to match the
// per-request `_meta.protocolVersion` value. // 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. // only when [StreamableHTTPOptions.Stateless] is true.
// //
// TODO: this validation can be moved within validateMcpHeaders. // 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 { if meta := extractRequestMeta(jreq.Params); meta != nil {
metaVersion, _ = meta[MetaKeyProtocolVersion].(string) 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 // Extract again the protcol version from the context to see what the client
// is advertising in the Mcp-Protocol-Version HTTP header. // is advertising in the Mcp-Protocol-Version HTTP header.
headerVersion := protocolVersionFromContext(req.Context()) 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) { jreq.Extra.(*RequestExtra).CloseSSEStream = func(args CloseSSEStreamArgs) {
// This mechanism was designed to trigger client reconnection with // This mechanism was designed to trigger client reconnection with
// Last-Event-ID for server-initiated disconnect scenarios. It is // Last-Event-ID for server-initiated disconnect scenarios. It is
// deprecated in protocol version 2026-06-30. // deprecated in protocol version 2026-07-28.
if protocolVersion >= protocolVersion20260630 { if protocolVersion >= protocolVersion20260728 {
return return
} }
c.mu.Lock() 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. // SSE mode: write a priming event if supported.
// //
// SEP-2575 removes Last-Event-ID-based resumable streams for protocol // SEP-2575 removes Last-Event-ID-based resumable streams for protocol
// version >= 2026-06-30. // version >= 2026-07-28.
if c.eventStore != nil && effectiveVersion >= protocolVersion20251125 && effectiveVersion < protocolVersion20260630 { if c.eventStore != nil && effectiveVersion >= protocolVersion20251125 && effectiveVersion < protocolVersion20260728 {
// Write a priming event, as defined by [§2.1.6] of the spec. // 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 // [§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 delivered := false
var errs []error var errs []error
protocolVersion := protocolVersionFromContext(ctx) 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 { if err := c.eventStore.Append(ctx, c.sessionID, s.id, data); err != nil {
errs = append(errs, err) errs = append(errs, err)
} else { } else {
@ -1765,12 +1765,12 @@ func (c *streamableServerConn) Write(ctx context.Context, msg jsonrpc.Message) e
// Compute eventID for SSE streams with event store. // Compute eventID for SSE streams with event store.
// Use s.lastIdx + 1 because deliverLocked increments before writing. // Use s.lastIdx + 1 because deliverLocked increments before writing.
var eventID string var eventID string
if c.eventStore != nil && protocolVersion < protocolVersion20260630 { if c.eventStore != nil && protocolVersion < protocolVersion20260728 {
eventID = formatEventID(s.id, s.lastIdx+1) eventID = formatEventID(s.id, s.lastIdx+1)
} }
// SEP-2575: map protocol-level JSON-RPC error codes to HTTP status codes // 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. // write the body as raw application/json with the override status.
overrideStatus := extractErrorStatus(ctx, msg) overrideStatus := extractErrorStatus(ctx, msg)
@ -1974,10 +1974,10 @@ func (c *streamableClientConn) sessionUpdated(state clientSessionState) {
c.initializedResult = state.InitializeResult c.initializedResult = state.InitializeResult
c.mu.Unlock() 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. // SSE stream is removed.
if state.InitializeResult == nil || if state.InitializeResult == nil ||
state.InitializeResult.ProtocolVersion >= protocolVersion20260630 { state.InitializeResult.ProtocolVersion >= protocolVersion20260728 {
return return
} }

View file

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

View file

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

View file

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