171 lines
5.6 KiB
Markdown
171 lines
5.6 KiB
Markdown
<!-- Autogenerated by weave; DO NOT EDIT -->
|
|
# Support for MCP client features
|
|
|
|
1. [Roots](#roots)
|
|
1. [Sampling](#sampling)
|
|
1. [Elicitation](#elicitation)
|
|
|
|
## Roots
|
|
|
|
MCP allows clients to specify a set of filesystem
|
|
["roots"](https://modelcontextprotocol.io/specification/2025-06-18/client/roots).
|
|
The SDK supports this as follows:
|
|
|
|
**Client-side**: The SDK client always has the `roots.listChanged` capability.
|
|
To add roots to a client, use the
|
|
[`Client.AddRoots`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#Client.AddRoots)
|
|
and
|
|
[`Client.RemoveRoots`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#Client.RemoveRoots)
|
|
methods. If any servers are already [connected](protocol.md#lifecycle) to the
|
|
client, a call to `AddRoot` or `RemoveRoots` will result in a
|
|
`notifications/roots/list_changed` notification to each connected server.
|
|
|
|
**Server-side**: To query roots from the server, use the
|
|
[`ServerSession.ListRoots`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ServerSession.ListRoots)
|
|
method. To receive notifications about root changes, set
|
|
[`ServerOptions.RootsListChangedHandler`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ServerOptions.RootsListChangedHandler).
|
|
|
|
```go
|
|
func Example_roots() {
|
|
ctx := context.Background()
|
|
|
|
// Create a client with a single root.
|
|
c := mcp.NewClient(&mcp.Implementation{Name: "client", Version: "v0.0.1"}, nil)
|
|
c.AddRoots(&mcp.Root{URI: "file://a"})
|
|
|
|
// Now create a server with a handler to receive notifications about roots.
|
|
rootsChanged := make(chan struct{})
|
|
handleRootsChanged := func(ctx context.Context, req *mcp.RootsListChangedRequest) {
|
|
rootList, err := req.Session.ListRoots(ctx, nil)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
var roots []string
|
|
for _, root := range rootList.Roots {
|
|
roots = append(roots, root.URI)
|
|
}
|
|
fmt.Println(roots)
|
|
close(rootsChanged)
|
|
}
|
|
s := mcp.NewServer(&mcp.Implementation{Name: "server", Version: "v0.0.1"}, &mcp.ServerOptions{
|
|
RootsListChangedHandler: handleRootsChanged,
|
|
})
|
|
|
|
// Connect the server and client...
|
|
t1, t2 := mcp.NewInMemoryTransports()
|
|
if _, err := s.Connect(ctx, t1, nil); err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
clientSession, err := c.Connect(ctx, t2, nil)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
defer clientSession.Close()
|
|
|
|
// ...and add a root. The server is notified about the change.
|
|
c.AddRoots(&mcp.Root{URI: "file://b"})
|
|
<-rootsChanged
|
|
// Output: [file://a file://b]
|
|
}
|
|
```
|
|
|
|
## Sampling
|
|
|
|
[Sampling](https://modelcontextprotocol.io/specification/2025-06-18/client/sampling)
|
|
is a way for servers to leverage the client's AI capabilities. It is
|
|
implemented in the SDK as follows:
|
|
|
|
**Client-side**: To add the `sampling` capability to a client, set
|
|
[`ClientOptions.CreateMessageHandler`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ClientOptions.CreateMessageHandler).
|
|
This function is invoked whenever the server requests sampling.
|
|
|
|
**Server-side**: To use sampling from the server, call
|
|
[`ServerSession.CreateMessage`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ServerSession.CreateMessage).
|
|
|
|
```go
|
|
func Example_sampling() {
|
|
ctx := context.Background()
|
|
|
|
// Create a client with a sampling handler.
|
|
c := mcp.NewClient(&mcp.Implementation{Name: "client", Version: "v0.0.1"}, &mcp.ClientOptions{
|
|
CreateMessageHandler: func(_ context.Context, req *mcp.CreateMessageRequest) (*mcp.CreateMessageResult, error) {
|
|
return &mcp.CreateMessageResult{
|
|
Content: &mcp.TextContent{
|
|
Text: "would have created a message",
|
|
},
|
|
}, nil
|
|
},
|
|
})
|
|
|
|
// Connect the server and client...
|
|
ct, st := mcp.NewInMemoryTransports()
|
|
s := mcp.NewServer(&mcp.Implementation{Name: "server", Version: "v0.0.1"}, nil)
|
|
session, err := s.Connect(ctx, st, nil)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
defer session.Close()
|
|
|
|
if _, err := c.Connect(ctx, ct, nil); err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
msg, err := session.CreateMessage(ctx, &mcp.CreateMessageParams{})
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
fmt.Println(msg.Content.(*mcp.TextContent).Text)
|
|
// Output: would have created a message
|
|
}
|
|
```
|
|
|
|
## Elicitation
|
|
|
|
[Elicitation](https://modelcontextprotocol.io/specification/2025-06-18/client/elicitation)
|
|
allows servers to request user inputs. It is implemented in the SDK as follows:
|
|
|
|
**Client-side**: To add the `elicitation` capability to a client, set
|
|
[`ClientOptions.ElicitationHandler`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ClientOptions.ElicitationHandler).
|
|
The elicitation handler must return a result that matches the requested schema;
|
|
otherwise, elicitation returns an error.
|
|
|
|
**Server-side**: To use elicitation from the server, call
|
|
[`ServerSession.Elicit`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ServerSession.Elicit).
|
|
|
|
```go
|
|
func Example_elicitation() {
|
|
ctx := context.Background()
|
|
ct, st := mcp.NewInMemoryTransports()
|
|
|
|
s := mcp.NewServer(&mcp.Implementation{Name: "server", Version: "v0.0.1"}, nil)
|
|
ss, err := s.Connect(ctx, st, nil)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
defer ss.Close()
|
|
|
|
c := mcp.NewClient(&mcp.Implementation{Name: "client", Version: "v0.0.1"}, &mcp.ClientOptions{
|
|
ElicitationHandler: func(context.Context, *mcp.ElicitRequest) (*mcp.ElicitResult, error) {
|
|
return &mcp.ElicitResult{Action: "accept", Content: map[string]any{"test": "value"}}, nil
|
|
},
|
|
})
|
|
if _, err := c.Connect(ctx, ct, nil); err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
res, err := ss.Elicit(ctx, &mcp.ElicitParams{
|
|
Message: "This should fail",
|
|
RequestedSchema: &jsonschema.Schema{
|
|
Type: "object",
|
|
Properties: map[string]*jsonschema.Schema{
|
|
"test": {Type: "string"},
|
|
},
|
|
},
|
|
})
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
fmt.Println(res.Content["test"])
|
|
// Output: value
|
|
}
|
|
```
|