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
This commit is contained in:
Robert Findley 2025-12-11 20:17:46 -05:00 • committed by GitHub
commit 3430e2242e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 1071 additions and 57 deletions

View file

@ -4,6 +4,9 @@
1. [Roots](#roots)
1. [Sampling](#sampling)
1. [Elicitation](#elicitation)
1. [Capabilities](#capabilities)
1. [Capability inference](#capability-inference)
1. [Explicit capabilities](#explicit-capabilities)
## Roots
@ -130,7 +133,9 @@ 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.
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).
@ -171,3 +176,60 @@ func Example_elicitation() {
// 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,
})
```

View file

@ -36,3 +36,12 @@ v2.
**Workaround**: use `ClientCapabilities.RootsV2`, which aligns with the
semantics of other capability fields.
- Default capabilities should have been empty. Instead, servers default to
advertising `logging`, and clients default to advertising `roots` with
`listChanged: true`. This is confusing because a nil `Capabilities` field
does not mean "no capabilities".
**Workaround**: to advertise no capabilities, set
`ServerOptions.Capabilities` or `ClientOptions.Capabilities` to an empty
`&ServerCapabilities{}` or `&ClientCapabilities{}` respectively.

View file

@ -7,6 +7,9 @@
1. [Utilities](#utilities)
1. [Completion](#completion)
1. [Logging](#logging)
1. [Capabilities](#capabilities)
1. [Capability inference](#capability-inference)
1. [Explicit capabilities](#explicit-capabilities)
1. [Pagination](#pagination)
## Prompts
@ -535,6 +538,53 @@ func Example_logging() {
}
```
## Capabilities
Server capabilities are advertised to clients during the initialization
handshake. By default, the SDK advertises only the `logging` capability.
Additional capabilities are automatically added when features are registered
(e.g., adding a tool adds the `tools` capability).
### Capability inference
When features such as tools, prompts, or resources are added to the server
(e.g., via `Server.AddTool`), their capability is automatically inferred, with
default value `{listChanged:true}`. Similarly, if the
`ServerOptions.SubscribeHandler` or `ServerOptions.CompletionHandler` are set,
the corresponding capability is added.
### Explicit capabilities
To explicitly declare capabilities, or to override the [default inferred
capability](#capability-inference), set
[`ServerOptions.Capabilities`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ServerOptions.Capabilities).
This sets the default server capabilities, before any capabilities are added
based on configured handlers. If a capability is already present as a field in
`Capabilities`, adding a feature or handler will not change its configuration.
This allows you to:
- **Disable default capabilities**: Pass an empty `&ServerCapabilities{}` to
disable all defaults, including logging.
- **Disable listChanged notifications**: Set `ListChanged: false` on a
capability to prevent the server from sending list-changed notifications
when features are added or removed.
- **Pre-declare capabilities**: Declare capabilities before features are
registered, useful for servers that load features dynamically.
```go
// Disable listChanged notifications for tools
server := mcp.NewServer(impl, &mcp.ServerOptions{
Capabilities: &mcp.ServerCapabilities{
Logging: &mcp.LoggingCapabilities{},
Tools: &mcp.ToolCapabilities{ListChanged: false},
},
})
```
**Deprecated**: The `HasPrompts`, `HasResources`, and `HasTools` fields on
`ServerOptions` are deprecated. Use `Capabilities` instead.
### Pagination
Server-side feature lists may be