From 5ae2a9f222fd1fc773e5f04e63f941ef8cd72c1c Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Wed, 18 Jun 2025 04:42:52 +0000 Subject: [PATCH] internal/mcp: update protocol versions Update protocol versions to reflect that 2025-03-26 is supported, and add server logic to negotiate the supported version with the client. Update the client to set the protocol version, fixing what was probably a spec violation. +tests Change-Id: I564b591b3daf018dd54f5c7e5d8f2d2b1e4ff502 Reviewed-on: https://go-review.googlesource.com/c/tools/+/682516 LUCI-TryBot-Result: Go LUCI Reviewed-by: Sam Thanawalla --- mcp/client.go | 8 +++- mcp/conformance_go124_test.go | 16 ++++++++ mcp/conformance_go125_test.go | 16 ++++++++ mcp/conformance_test.go | 4 +- mcp/server.go | 11 ++++- mcp/streamable_test.go | 2 +- .../conformance/server/version-latest.txtar | 40 +++++++++++++++++++ .../conformance/server/version-older.txtar | 40 +++++++++++++++++++ 8 files changed, 130 insertions(+), 7 deletions(-) create mode 100644 mcp/conformance_go124_test.go create mode 100644 mcp/conformance_go125_test.go create mode 100644 mcp/testdata/conformance/server/version-latest.txtar create mode 100644 mcp/testdata/conformance/server/version-older.txtar diff --git a/mcp/client.go b/mcp/client.go index 55d80f3..9686413 100644 --- a/mcp/client.go +++ b/mcp/client.go @@ -101,9 +101,13 @@ func (c *Client) Connect(ctx context.Context, t Transport) (cs *ClientSession, e } params := &InitializeParams{ - ClientInfo: &implementation{Name: c.name, Version: c.version}, - Capabilities: caps, + ClientInfo: &implementation{Name: c.name, Version: c.version}, + Capabilities: caps, + ProtocolVersion: "2025-03-26", } + // TODO(rfindley): handle protocol negotiation gracefully. If the server + // responds with 2024-11-05, surface that failure to the caller of connect, + // so that they can choose a different transport. res, err := handleSend[*InitializeResult](ctx, cs, methodInitialize, params) if err != nil { _ = cs.Close() diff --git a/mcp/conformance_go124_test.go b/mcp/conformance_go124_test.go new file mode 100644 index 0000000..3135970 --- /dev/null +++ b/mcp/conformance_go124_test.go @@ -0,0 +1,16 @@ +// Copyright 2025 The Go MCP SDK Authors. All rights reserved. +// Use of this source code is governed by an MIT-style +// license that can be found in the LICENSE file. + +//go:build go1.24 && goexperiment.synctest + +package mcp + +import ( + "testing" + "testing/synctest" +) + +func runSyncTest(t *testing.T, f func(t *testing.T)) { + synctest.Run(func() { f(t) }) +} diff --git a/mcp/conformance_go125_test.go b/mcp/conformance_go125_test.go new file mode 100644 index 0000000..c1bb0e1 --- /dev/null +++ b/mcp/conformance_go125_test.go @@ -0,0 +1,16 @@ +// Copyright 2025 The Go MCP SDK Authors. All rights reserved. +// Use of this source code is governed by an MIT-style +// license that can be found in the LICENSE file. + +//go:build go1.25 + +package mcp + +import ( + "testing" + "testing/synctest" +) + +func runSyncTest(t *testing.T, f func(t *testing.T)) { + synctest.Test(t, f) +} diff --git a/mcp/conformance_test.go b/mcp/conformance_test.go index 6886d67..b793e3e 100644 --- a/mcp/conformance_test.go +++ b/mcp/conformance_test.go @@ -2,7 +2,7 @@ // Use of this source code is governed by an MIT-style // license that can be found in the LICENSE file. -//go:build go1.24 && goexperiment.synctest +//go:build (go1.24 && goexperiment.synctest) || go1.25 package mcp @@ -85,7 +85,7 @@ func TestServerConformance(t *testing.T) { // By comparison, gopls has a complicated framework based on progress // reporting and careful accounting to detect when all 'expected' work // on the server is complete. - synctest.Run(func() { runServerTest(t, test) }) + runSyncTest(t, func(t *testing.T) { runServerTest(t, test) }) // TODO: in 1.25, use the following instead: // synctest.Test(t, func(t *testing.T) { diff --git a/mcp/server.go b/mcp/server.go index 198d9d3..8d25ad9 100644 --- a/mcp/server.go +++ b/mcp/server.go @@ -634,9 +634,16 @@ func (ss *ServerSession) initialize(ctx context.Context, params *InitializeParam ss.mu.Unlock() }() + version := "2025-03-26" // preferred version + switch v := params.ProtocolVersion; v { + case "2024-11-05", "2025-03-26": + version = v + } + return &InitializeResult{ - // TODO(rfindley): support multiple protocol versions. - ProtocolVersion: "2024-11-05", + // TODO(rfindley): alter behavior when falling back to an older version: + // reject unsupported features. + ProtocolVersion: version, Capabilities: &serverCapabilities{ Prompts: &promptCapabilities{ ListChanged: true, diff --git a/mcp/streamable_test.go b/mcp/streamable_test.go index 8aad124..c964157 100644 --- a/mcp/streamable_test.go +++ b/mcp/streamable_test.go @@ -122,7 +122,7 @@ func TestStreamableServerTransport(t *testing.T) { Resources: &resourceCapabilities{ListChanged: true}, Tools: &toolCapabilities{ListChanged: true}, }, - ProtocolVersion: "2024-11-05", + ProtocolVersion: "2025-03-26", ServerInfo: &implementation{Name: "testServer", Version: "v1.0.0"}, }, nil) initializedMsg := req(0, "initialized", &InitializedParams{}) diff --git a/mcp/testdata/conformance/server/version-latest.txtar b/mcp/testdata/conformance/server/version-latest.txtar new file mode 100644 index 0000000..c81b583 --- /dev/null +++ b/mcp/testdata/conformance/server/version-latest.txtar @@ -0,0 +1,40 @@ +Check that when the client sends an arbitrary later version, the server +response with its latest supported version. + +-- client -- +{ + "jsonrpc": "2.0", + "id": 1, + "method": "initialize", + "params": { + "protocolVersion": "2029-01-01", + "capabilities": {}, + "clientInfo": { "name": "ExampleClient", "version": "1.0.0" } + } +} +-- server -- +{ + "jsonrpc": "2.0", + "id": 1, + "result": { + "_meta": {}, + "capabilities": { + "completions": {}, + "logging": {}, + "prompts": { + "listChanged": true + }, + "resources": { + "listChanged": true + }, + "tools": { + "listChanged": true + } + }, + "protocolVersion": "2025-03-26", + "serverInfo": { + "name": "testServer", + "version": "v1.0.0" + } + } +} diff --git a/mcp/testdata/conformance/server/version-older.txtar b/mcp/testdata/conformance/server/version-older.txtar new file mode 100644 index 0000000..215b22e --- /dev/null +++ b/mcp/testdata/conformance/server/version-older.txtar @@ -0,0 +1,40 @@ +Check that when the client sends an older version, the server indicates +support. + +-- client -- +{ + "jsonrpc": "2.0", + "id": 1, + "method": "initialize", + "params": { + "protocolVersion": "2024-11-05", + "capabilities": {}, + "clientInfo": { "name": "ExampleClient", "version": "1.0.0" } + } +} +-- server -- +{ + "jsonrpc": "2.0", + "id": 1, + "result": { + "_meta": {}, + "capabilities": { + "completions": {}, + "logging": {}, + "prompts": { + "listChanged": true + }, + "resources": { + "listChanged": true + }, + "tools": { + "listChanged": true + } + }, + "protocolVersion": "2024-11-05", + "serverInfo": { + "name": "testServer", + "version": "v1.0.0" + } + } +}