go-sdk/docs/client.md
Robert Findley 3430e2242e
mcp: add Capabilities fields to ServerOptions and ClientOptions (#713)
This allows users to configure default capabilities, disable defaults,
or suppress listChanged notifications by setting ListChanged: false.

Key changes:
- Add ServerOptions.Capabilities and ClientOptions.Capabilities fields.
- Merge user-provided capabilities with dynamically-added ones (tools,
  prompts, resources, sampling, elicitation).
- Check ListChanged before sending list-changed notifications.
- Deprecate HasPrompts, HasResources, HasTools on ServerOptions.
- Remove unreleased ElicitationModes field from ClientOptions.
- Add clone methods to capability structs using shallowClone helper.
- Add synctest-based tests for notification behavior (go1.25).
- Add TestClientCapabilitiesOverWire and TestServerCapabilitiesOverWire
- Document the new Capabilities API in docs/

Updates #706
2025-12-11 20:17:46 -05:00

235 lines
8.3 KiB
Markdown

<!-- Autogenerated by weave; DO NOT EDIT -->
# Support for MCP client features
1. [Roots](#roots)
1. [Sampling](#sampling)
1. [Elicitation](#elicitation)
1. [Capabilities](#capabilities)
1. [Capability inference](#capability-inference)
1. [Explicit capabilities](#explicit-capabilities)
## 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()
serverSession, err := s.Connect(ctx, t1, nil)
if err != nil {
log.Fatal(err)
}
defer serverSession.Close()
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. If your handler supports [URL mode
elicitation](https://modelcontextprotocol.io/specification/2025-11-25/client/elicitation#url-mode-elicitation-requests),
you must declare that capability explicitly (see [Capabilities](#capabilities))
**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
}
```
## Capabilities
Client capabilities are advertised to servers during the initialization
handshake. [By default](rough_edges.md), the SDK advertises the `logging`
capability. Additional capabilities are automatically added when server
features are added (e.g. via `AddTool`), or when handlers are set in the
`ServerOptions` struct (e.g., setting `CompletionHandler` adds the
`completions` capability), or may be configured explicitly.
### Capability inference
When handlers are set on `ClientOptions` (e.g., `CreateMessageHandler` or
`ElicitationHandler`), the corresponding capability is automatically added if
not already present, with a default configuration.
For elicitation, if the handler is set but no `Capabilities.Elicitation` is
specified, the client defaults to form elicitation. To enable URL elicitation
or both modes, [configure `Capabilities.Elicitation`
explicitly](#explicit-capabilities).
See the [`ClientCapabilities`
documentation](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ClientCapabilities)
for further details on inference.
### Explicit capabilities
To explicitly declare capabilities, or to override the [default inferred
capability](#capability-inference), set
[`ClientOptions.Capabilities`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ClientOptions.Capabilities).
This sets the initial client capabilities, before any capabilities are added
based on configured handlers. If a capability is already present in
`Capabilities`, adding a handler will not change its configuration.
This allows you to:
- **Disable default capabilities**: Pass an empty `&ClientCapabilities{}` to
disable all defaults, including roots.
- **Disable listChanged notifications**: Set `ListChanged: false` on a
capability to prevent the client from sending list-changed notifications
when roots are added or removed.
- **Configure elicitation modes**: Specify which elicitation modes (form, URL)
the client supports.
```go
// Configure elicitation modes and disable roots.
client := mcp.NewClient(impl, &mcp.ClientOptions{
Capabilities: &mcp.ClientCapabilities{
Elicitation: &mcp.ElicitationCapabilities{
Form: &mcp.FormElicitationCapabilities{},
URL: &mcp.URLElicitationCapabilities{},
},
},
ElicitationHandler: handler,
})
```