internal/mcp: add resource conformance test

This uncovered a problem in how we represent resource results:
contents is a slice, not a single value.

I tried to use a file resource, but the server->client ListRoots
call didn't work because synthetic responses aren't supported.
Left a TODO.

I enhanced the hello example so I that could use the MCP Inspector to
work with resources.

The falseSchema change fixes a potential bug where schemas are
re-used, which is disallowed.

Change-Id: I1f0198043cb6221c2a03f4f83aa0bafbc71167f4
Reviewed-on: https://go-review.googlesource.com/c/tools/+/677136
Reviewed-by: Robert Findley <rfindley@google.com>
Reviewed-by: Sam Thanawalla <samthanawalla@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Auto-Submit: Jonathan Amsterdam <jba@google.com>
This commit is contained in:
Jonathan Amsterdam 2025-05-29 07:57:10 -04:00 • committed by Gopher Robot
commit a627a4a2dd

View file

@ -24,7 +24,6 @@ import (
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
"github.com/modelcontextprotocol/go-sdk/internal/jsonrpc2"
"golang.org/x/tools/internal/testenv"
"golang.org/x/tools/txtar"
)
@ -56,10 +55,10 @@ type conformanceTest struct {
server []jsonrpc2.Message // server messages
}
// TODO(jba): support synthetic responses.
// TODO(rfindley): add client conformance tests.
func TestServerConformance(t *testing.T) {
testenv.NeedsGoExperiment(t, "synctest")
var tests []*conformanceTest
dir := filepath.Join("testdata", "conformance", "server")
if err := filepath.WalkDir(dir, func(path string, _ fs.DirEntry, err error) error {
@ -245,7 +244,7 @@ func loadConformanceTest(dir, path string) (*conformanceTest, error) {
// loadFeatures loads lists of named features from the archive file.
loadFeatures := func(data []byte) []string {
var feats []string
for line := range strings.SplitSeq(string(data), "\n") {
for line := range strings.Lines(string(data)) {
if f := strings.TrimSpace(line); f != "" {
feats = append(feats, f)
}
@ -264,7 +263,7 @@ func loadConformanceTest(dir, path string) (*conformanceTest, error) {
test.tools = loadFeatures(f.Data)
case "prompts":
test.prompts = loadFeatures(f.Data)
case "resource":
case "resources":
test.resources = loadFeatures(f.Data)
case "client":
test.client, err = decodeMessages(f.Data)