docs: document resources (#505)

This commit is contained in:
Jonathan Amsterdam 2025-09-19 11:46:50 -04:00 • committed by GitHub
commit 4fa725857c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 249 additions and 2 deletions

View file

@ -109,7 +109,129 @@ func Example_prompts() {
## Resources
<!-- TODO -->
In MCP terms, a _resource_ is some data referenced by a URI.
MCP servers can serve resources to clients.
They can register resources individually, or register a _resource template_
that uses a URI pattern to describe a collection of resources.
**Client-side**:
Call [`ClientSession.ReadResource`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ClientSession.ReadResource)
to read a resource.
The SDK ensures that a read succeeds only if the URI matches a registered resource exactly,
or matches the URI pattern of a resource template.
To list a server's resources and resource templates, use the
[`ClientSession.Resources`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ClientSession.Resources)
and
[`ClientSession.ResourceTemplates`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ClientSession.ResourceTemplates)
iterators, or the lower-level `ListXXX` calls (see [pagination](#pagination)).
Set
[`ClientOptions.ResourceListChangedHandler`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ClientOptions.ResourceListChangedHandler)
to be notified of changes in the lists of resources or resource templates.
Clients can be notified when the contents of a resource changes by subscribing to the resource's URI.
Call
[`ClientSession.Subscribe`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ClientSession.Subscribe)
to subscribe to a resource
and
[`ClientSession.Unsubscribe`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ClientSession.Unsubscribe)
to unsubscribe.
Set
[`ClientOptions.ResourceUpdatedHandler`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ClientOptions.ResourceUpdatedHandler)
to be notified of changes to subscribed resources.
**Server-side**:
Use
[`Server.AddResource`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#Server.AddResource)
or
[`Server.AddResourceTemplate`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#Server.AddResourceTemplate)
to add a resource or resource template to the server along with its handler.
A
[`ResourceHandler`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ResourceHandler)
maps a URI to the contents of a resource, which can include text, binary data,
or both.
If `AddResource` or `AddResourceTemplate` is called before a server is connected, the server will have the
`resources` capability.
The server will have the `resources` capability if any resource or resource template is added before the
server is connected to a client, or if
[`ServerOptions.HasResources`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ServerOptions.HasResources)
is explicitly set. When a prompt is added, any clients already connected to the
server will be notified via a `notifications/resources/list_changed`
notification.
```go
func Example_resources() {
ctx := context.Background()
resources := map[string]string{
"file:///a": "a",
"file:///dir/x": "x",
"file:///dir/y": "y",
}
handler := func(_ context.Context, req *mcp.ReadResourceRequest) (*mcp.ReadResourceResult, error) {
uri := req.Params.URI
c, ok := resources[uri]
if !ok {
return nil, mcp.ResourceNotFoundError(uri)
}
return &mcp.ReadResourceResult{
Contents: []*mcp.ResourceContents{{URI: uri, Text: c}},
}, nil
}
// Create a server with a single resource.
s := mcp.NewServer(&mcp.Implementation{Name: "server", Version: "v0.0.1"}, nil)
s.AddResource(&mcp.Resource{URI: "file:///a"}, handler)
s.AddResourceTemplate(&mcp.ResourceTemplate{URITemplate: "file:///dir/{f}"}, handler)
// Create a client.
c := mcp.NewClient(&mcp.Implementation{Name: "client", Version: "v0.0.1"}, nil)
// Connect the server and client.
t1, t2 := mcp.NewInMemoryTransports()
if _, err := s.Connect(ctx, t1, nil); err != nil {
log.Fatal(err)
}
cs, err := c.Connect(ctx, t2, nil)
if err != nil {
log.Fatal(err)
}
defer cs.Close()
// List resources and resource templates.
for r, err := range cs.Resources(ctx, nil) {
if err != nil {
log.Fatal(err)
}
fmt.Println(r.URI)
}
for r, err := range cs.ResourceTemplates(ctx, nil) {
if err != nil {
log.Fatal(err)
}
fmt.Println(r.URITemplate)
}
// Read resources.
for _, path := range []string{"a", "dir/x", "b"} {
res, err := cs.ReadResource(ctx, &mcp.ReadResourceParams{URI: "file:///" + path})
if err != nil {
fmt.Println(err)
} else {
fmt.Println(res.Contents[0].Text)
}
}
// Output:
// file:///a
// file:///dir/{f}
// a
// x
// calling "resources/read": Resource not found
}
```
## Tools

View file

@ -35,7 +35,59 @@ notification.
## Resources
<!-- TODO -->
In MCP terms, a _resource_ is some data referenced by a URI.
MCP servers can serve resources to clients.
They can register resources individually, or register a _resource template_
that uses a URI pattern to describe a collection of resources.
**Client-side**:
Call [`ClientSession.ReadResource`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ClientSession.ReadResource)
to read a resource.
The SDK ensures that a read succeeds only if the URI matches a registered resource exactly,
or matches the URI pattern of a resource template.
To list a server's resources and resource templates, use the
[`ClientSession.Resources`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ClientSession.Resources)
and
[`ClientSession.ResourceTemplates`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ClientSession.ResourceTemplates)
iterators, or the lower-level `ListXXX` calls (see [pagination](#pagination)).
Set
[`ClientOptions.ResourceListChangedHandler`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ClientOptions.ResourceListChangedHandler)
to be notified of changes in the lists of resources or resource templates.
Clients can be notified when the contents of a resource changes by subscribing to the resource's URI.
Call
[`ClientSession.Subscribe`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ClientSession.Subscribe)
to subscribe to a resource
and
[`ClientSession.Unsubscribe`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ClientSession.Unsubscribe)
to unsubscribe.
Set
[`ClientOptions.ResourceUpdatedHandler`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ClientOptions.ResourceUpdatedHandler)
to be notified of changes to subscribed resources.
**Server-side**:
Use
[`Server.AddResource`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#Server.AddResource)
or
[`Server.AddResourceTemplate`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#Server.AddResourceTemplate)
to add a resource or resource template to the server along with its handler.
A
[`ResourceHandler`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ResourceHandler)
maps a URI to the contents of a resource, which can include text, binary data,
or both.
If `AddResource` or `AddResourceTemplate` is called before a server is connected, the server will have the
`resources` capability.
The server will have the `resources` capability if any resource or resource template is added before the
server is connected to a client, or if
[`ServerOptions.HasResources`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ServerOptions.HasResources)
is explicitly set. When a prompt is added, any clients already connected to the
server will be notified via a `notifications/resources/list_changed`
notification.
%include ../../mcp/server_example_test.go resources -
## Tools

View file

@ -82,3 +82,76 @@ func Example_prompts() {
}
// !-prompts
// !+resources
func Example_resources() {
ctx := context.Background()
resources := map[string]string{
"file:///a": "a",
"file:///dir/x": "x",
"file:///dir/y": "y",
}
handler := func(_ context.Context, req *mcp.ReadResourceRequest) (*mcp.ReadResourceResult, error) {
uri := req.Params.URI
c, ok := resources[uri]
if !ok {
return nil, mcp.ResourceNotFoundError(uri)
}
return &mcp.ReadResourceResult{
Contents: []*mcp.ResourceContents{{URI: uri, Text: c}},
}, nil
}
// Create a server with a single resource.
s := mcp.NewServer(&mcp.Implementation{Name: "server", Version: "v0.0.1"}, nil)
s.AddResource(&mcp.Resource{URI: "file:///a"}, handler)
s.AddResourceTemplate(&mcp.ResourceTemplate{URITemplate: "file:///dir/{f}"}, handler)
// Create a client.
c := mcp.NewClient(&mcp.Implementation{Name: "client", Version: "v0.0.1"}, nil)
// Connect the server and client.
t1, t2 := mcp.NewInMemoryTransports()
if _, err := s.Connect(ctx, t1, nil); err != nil {
log.Fatal(err)
}
cs, err := c.Connect(ctx, t2, nil)
if err != nil {
log.Fatal(err)
}
defer cs.Close()
// List resources and resource templates.
for r, err := range cs.Resources(ctx, nil) {
if err != nil {
log.Fatal(err)
}
fmt.Println(r.URI)
}
for r, err := range cs.ResourceTemplates(ctx, nil) {
if err != nil {
log.Fatal(err)
}
fmt.Println(r.URITemplate)
}
// Read resources.
for _, path := range []string{"a", "dir/x", "b"} {
res, err := cs.ReadResource(ctx, &mcp.ReadResourceParams{URI: "file:///" + path})
if err != nil {
fmt.Println(err)
} else {
fmt.Println(res.Contents[0].Text)
}
}
// Output:
// file:///a
// file:///dir/{f}
// a
// x
// calling "resources/read": Resource not found
}
// !-resources