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:
parent
b85574f685
commit
17029489ff
13 changed files with 137 additions and 137 deletions
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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).
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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{},
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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: ¶ms}
|
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)
|
t.Errorf("ProtocolVersion = %q, want %q", got, want)
|
||||||
}
|
}
|
||||||
gotInfo := req.ClientInfo()
|
gotInfo := req.ClientInfo()
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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 = "?="
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue