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

@ -9,6 +9,7 @@ import (
"flag"
"fmt"
"net/http"
"net/url"
"os"
"github.com/modelcontextprotocol/go-sdk/mcp"
@ -43,6 +44,14 @@ func main() {
mcp.Property("name", mcp.Description("the name to say hi to")),
)))
server.AddPrompts(mcp.NewPrompt("greet", "", PromptHi))
server.AddResources(&mcp.ServerResource{
Resource: &mcp.Resource{
Name: "info",
MIMEType: "text/plain",
URI: "embedded:info",
},
Handler: handleEmbeddedResource,
})
if *httpAddr != "" {
handler := mcp.NewSSEHandler(func(*http.Request) *mcp.Server {
@ -56,3 +65,25 @@ func main() {
}
}
}
var embeddedResources = map[string]string{
"info": "This is the hello example server.",
}
func handleEmbeddedResource(_ context.Context, _ *mcp.ServerSession, params *mcp.ReadResourceParams) (*mcp.ReadResourceResult, error) {
u, err := url.Parse(params.URI)
if err != nil {
return nil, err
}
if u.Scheme != "embedded" {
return nil, fmt.Errorf("wrong scheme: %q", u.Scheme)
}
key := u.Opaque
text, ok := embeddedResources[key]
if !ok {
return nil, fmt.Errorf("no embedded resource named %q", key)
}
return &mcp.ReadResourceResult{
Contents: []*mcp.ResourceContents{mcp.NewTextResourceContents(params.URI, "text/plain", text)},
}, nil
}