From 17029489fff03e9577d45424be90459dd3d25bee Mon Sep 17 00:00:00 2001 From: Guglielmo Colombo Date: Mon, 22 Jun 2026 09:53:04 +0200 Subject: [PATCH] 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. --- mcp/client.go | 12 ++++---- mcp/client_test.go | 48 +++++++++++++++---------------- mcp/mrtr.go | 2 +- mcp/mrtr_test.go | 16 +++++------ mcp/protocol.go | 2 +- mcp/server.go | 6 ++-- mcp/server_test.go | 14 ++++----- mcp/shared.go | 14 ++++----- mcp/shared_test.go | 22 +++++++------- mcp/streamable.go | 44 ++++++++++++++-------------- mcp/streamable_client_test.go | 38 ++++++++++++------------ mcp/streamable_headers.go | 2 +- mcp/streamable_test.go | 54 +++++++++++++++++------------------ 13 files changed, 137 insertions(+), 137 deletions(-) diff --git a/mcp/client.go b/mcp/client.go index b89b962..785b186 100644 --- a/mcp/client.go +++ b/mcp/client.go @@ -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 diff --git a/mcp/client_test.go b/mcp/client_test.go index d6f0232..5e3a94a 100644 --- a/mcp/client_test.go +++ b/mcp/client_test.go @@ -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) } } diff --git a/mcp/mrtr.go b/mcp/mrtr.go index 8ad5f1a..5f65f56 100644 --- a/mcp/mrtr.go +++ b/mcp/mrtr.go @@ -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 { diff --git a/mcp/mrtr_test.go b/mcp/mrtr_test.go index 230eb3b..c0335d8 100644 --- a/mcp/mrtr_test.go +++ b/mcp/mrtr_test.go @@ -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) } diff --git a/mcp/protocol.go b/mcp/protocol.go index 5447212..4b0872b 100644 --- a/mcp/protocol.go +++ b/mcp/protocol.go @@ -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). diff --git a/mcp/server.go b/mcp/server.go index a53cb64..af59b40 100644 --- a/mcp/server.go +++ b/mcp/server.go @@ -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) diff --git a/mcp/server_test.go b/mcp/server_test.go index 4c8b76e..f6938d1 100644 --- a/mcp/server_test.go +++ b/mcp/server_test.go @@ -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{}, }, diff --git a/mcp/shared.go b/mcp/shared.go index ae1ee3c..128cbc2 100644 --- a/mcp/shared.go +++ b/mcp/shared.go @@ -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 { diff --git a/mcp/shared_test.go b/mcp/shared_test.go index 62f6583..08c202a 100644 --- a/mcp/shared_test.go +++ b/mcp/shared_test.go @@ -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: ¶ms} - 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() diff --git a/mcp/streamable.go b/mcp/streamable.go index 3d2de97..2d020c6 100644 --- a/mcp/streamable.go +++ b/mcp/streamable.go @@ -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 } diff --git a/mcp/streamable_client_test.go b/mcp/streamable_client_test.go index 2e372af..24179d1 100644 --- a/mcp/streamable_client_test.go +++ b/mcp/streamable_client_test.go @@ -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) } } diff --git a/mcp/streamable_headers.go b/mcp/streamable_headers.go index af9ff39..3989c01 100644 --- a/mcp/streamable_headers.go +++ b/mcp/streamable_headers.go @@ -27,7 +27,7 @@ const ( methodHeader = "Mcp-Method" nameHeader = "Mcp-Name" paramHeaderPrefix = "Mcp-Param-" - minVersionForStandardHeaders = protocolVersion20260630 + minVersionForStandardHeaders = protocolVersion20260728 base64Prefix = "=?base64?" base64Suffix = "?=" ) diff --git a/mcp/streamable_test.go b/mcp/streamable_test.go index 79934b4..a9855cb 100644 --- a/mcp/streamable_test.go +++ b/mcp/streamable_test.go @@ -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)