Skip to content

Commit d257480

Browse files
committed
mcp: add Capabilities fields to ServerOptions and ClientOptions
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
1 parent bae0929 commit d257480

File tree

14 files changed

+1071
-57
lines changed

14 files changed

+1071
-57
lines changed

docs/client.md

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44
1. [Roots](#roots)
55
1. [Sampling](#sampling)
66
1. [Elicitation](#elicitation)
7+
1. [Capabilities](#capabilities)
8+
1. [Capability inference](#capability-inference)
9+
1. [Explicit capabilities](#explicit-capabilities)
710

811
## Roots
912

@@ -130,7 +133,9 @@ allows servers to request user inputs. It is implemented in the SDK as follows:
130133
**Client-side**: To add the `elicitation` capability to a client, set
131134
[`ClientOptions.ElicitationHandler`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ClientOptions.ElicitationHandler).
132135
The elicitation handler must return a result that matches the requested schema;
133-
otherwise, elicitation returns an error.
136+
otherwise, elicitation returns an error. If your handler supports [URL mode
137+
elicitation](https://modelcontextprotocol.io/specification/2025-11-25/client/elicitation#url-mode-elicitation-requests),
138+
you must declare that capability explicitly (see [Capabilities](#capabilities))
134139

135140
**Server-side**: To use elicitation from the server, call
136141
[`ServerSession.Elicit`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ServerSession.Elicit).
@@ -171,3 +176,60 @@ func Example_elicitation() {
171176
// Output: value
172177
}
173178
```
179+
180+
## Capabilities
181+
182+
Client capabilities are advertised to servers during the initialization
183+
handshake. [By default](rough_edges.md), the SDK advertises the `logging`
184+
capability. Additional capabilities are automatically added when server
185+
features are added (e.g. via `AddTool`), or when handlers are set in the
186+
`ServerOptions` struct (e.g., setting `CompletionHandler` adds the
187+
`completions` capability), or may be configured explicitly.
188+
189+
### Capability inference
190+
191+
When handlers are set on `ClientOptions` (e.g., `CreateMessageHandler` or
192+
`ElicitationHandler`), the corresponding capability is automatically added if
193+
not already present, with a default configuration.
194+
195+
For elicitation, if the handler is set but no `Capabilities.Elicitation` is
196+
specified, the client defaults to form elicitation. To enable URL elicitation
197+
or both modes, [configure `Capabilities.Elicitation`
198+
explicitly](#explicit-capabilities).
199+
200+
See the [`ClientCapabilities`
201+
documentation](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ClientCapabilities)
202+
for further details on inference.
203+
204+
### Explicit capabilities
205+
206+
To explicitly declare capabilities, or to override the [default inferred
207+
capability](#capability-inference), set
208+
[`ClientOptions.Capabilities`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ClientOptions.Capabilities).
209+
This sets the initial client capabilities, before any capabilities are added
210+
based on configured handlers. If a capability is already present in
211+
`Capabilities`, adding a handler will not change its configuration.
212+
213+
This allows you to:
214+
215+
- **Disable default capabilities**: Pass an empty `&ClientCapabilities{}` to
216+
disable all defaults, including roots.
217+
- **Disable listChanged notifications**: Set `ListChanged: false` on a
218+
capability to prevent the client from sending list-changed notifications
219+
when roots are added or removed.
220+
- **Configure elicitation modes**: Specify which elicitation modes (form, URL)
221+
the client supports.
222+
223+
```go
224+
// Configure elicitation modes and disable roots.
225+
client := mcp.NewClient(impl, &mcp.ClientOptions{
226+
Capabilities: &mcp.ClientCapabilities{
227+
Elicitation: &mcp.ElicitationCapabilities{
228+
Form: &mcp.FormElicitationCapabilities{},
229+
URL: &mcp.URLElicitationCapabilities{},
230+
},
231+
},
232+
ElicitationHandler: handler,
233+
})
234+
```
235+

docs/rough_edges.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,12 @@ v2.
3636

3737
**Workaround**: use `ClientCapabilities.RootsV2`, which aligns with the
3838
semantics of other capability fields.
39+
40+
- Default capabilities should have been empty. Instead, servers default to
41+
advertising `logging`, and clients default to advertising `roots` with
42+
`listChanged: true`. This is confusing because a nil `Capabilities` field
43+
does not mean "no capabilities".
44+
45+
**Workaround**: to advertise no capabilities, set
46+
`ServerOptions.Capabilities` or `ClientOptions.Capabilities` to an empty
47+
`&ServerCapabilities{}` or `&ClientCapabilities{}` respectively.

docs/server.md

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
1. [Utilities](#utilities)
88
1. [Completion](#completion)
99
1. [Logging](#logging)
10+
1. [Capabilities](#capabilities)
11+
1. [Capability inference](#capability-inference)
12+
1. [Explicit capabilities](#explicit-capabilities)
1013
1. [Pagination](#pagination)
1114

1215
## Prompts
@@ -535,6 +538,53 @@ func Example_logging() {
535538
}
536539
```
537540

541+
## Capabilities
542+
543+
Server capabilities are advertised to clients during the initialization
544+
handshake. By default, the SDK advertises only the `logging` capability.
545+
Additional capabilities are automatically added when features are registered
546+
(e.g., adding a tool adds the `tools` capability).
547+
548+
### Capability inference
549+
550+
When features such as tools, prompts, or resources are added to the server
551+
(e.g., via `Server.AddTool`), their capability is automatically inferred, with
552+
default value `{listChanged:true}`. Similarly, if the
553+
`ServerOptions.SubscribeHandler` or `ServerOptions.CompletionHandler` are set,
554+
the corresponding capability is added.
555+
556+
### Explicit capabilities
557+
558+
To explicitly declare capabilities, or to override the [default inferred
559+
capability](#capability-inference), set
560+
[`ServerOptions.Capabilities`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ServerOptions.Capabilities).
561+
This sets the default server capabilities, before any capabilities are added
562+
based on configured handlers. If a capability is already present as a field in
563+
`Capabilities`, adding a feature or handler will not change its configuration.
564+
565+
This allows you to:
566+
567+
- **Disable default capabilities**: Pass an empty `&ServerCapabilities{}` to
568+
disable all defaults, including logging.
569+
- **Disable listChanged notifications**: Set `ListChanged: false` on a
570+
capability to prevent the server from sending list-changed notifications
571+
when features are added or removed.
572+
- **Pre-declare capabilities**: Declare capabilities before features are
573+
registered, useful for servers that load features dynamically.
574+
575+
```go
576+
// Disable listChanged notifications for tools
577+
server := mcp.NewServer(impl, &mcp.ServerOptions{
578+
Capabilities: &mcp.ServerCapabilities{
579+
Logging: &mcp.LoggingCapabilities{},
580+
Tools: &mcp.ToolCapabilities{ListChanged: false},
581+
},
582+
})
583+
```
584+
585+
**Deprecated**: The `HasPrompts`, `HasResources`, and `HasTools` fields on
586+
`ServerOptions` are deprecated. Use `Capabilities` instead.
587+
538588
### Pagination
539589

540590
Server-side feature lists may be

internal/docs/client.src.md

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,68 @@ allows servers to request user inputs. It is implemented in the SDK as follows:
4747
**Client-side**: To add the `elicitation` capability to a client, set
4848
[`ClientOptions.ElicitationHandler`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ClientOptions.ElicitationHandler).
4949
The elicitation handler must return a result that matches the requested schema;
50-
otherwise, elicitation returns an error.
50+
otherwise, elicitation returns an error. If your handler supports [URL mode
51+
elicitation](https://modelcontextprotocol.io/specification/2025-11-25/client/elicitation#url-mode-elicitation-requests),
52+
you must declare that capability explicitly (see [Capabilities](#capabilities))
5153

5254
**Server-side**: To use elicitation from the server, call
5355
[`ServerSession.Elicit`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ServerSession.Elicit).
5456

5557
%include ../../mcp/client_example_test.go elicitation -
58+
59+
## Capabilities
60+
61+
Client capabilities are advertised to servers during the initialization
62+
handshake. [By default](rough_edges.md), the SDK advertises the `logging`
63+
capability. Additional capabilities are automatically added when server
64+
features are added (e.g. via `AddTool`), or when handlers are set in the
65+
`ServerOptions` struct (e.g., setting `CompletionHandler` adds the
66+
`completions` capability), or may be configured explicitly.
67+
68+
### Capability inference
69+
70+
When handlers are set on `ClientOptions` (e.g., `CreateMessageHandler` or
71+
`ElicitationHandler`), the corresponding capability is automatically added if
72+
not already present, with a default configuration.
73+
74+
For elicitation, if the handler is set but no `Capabilities.Elicitation` is
75+
specified, the client defaults to form elicitation. To enable URL elicitation
76+
or both modes, [configure `Capabilities.Elicitation`
77+
explicitly](#explicit-capabilities).
78+
79+
See the [`ClientCapabilities`
80+
documentation](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ClientCapabilities)
81+
for further details on inference.
82+
83+
### Explicit capabilities
84+
85+
To explicitly declare capabilities, or to override the [default inferred
86+
capability](#capability-inference), set
87+
[`ClientOptions.Capabilities`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ClientOptions.Capabilities).
88+
This sets the initial client capabilities, before any capabilities are added
89+
based on configured handlers. If a capability is already present in
90+
`Capabilities`, adding a handler will not change its configuration.
91+
92+
This allows you to:
93+
94+
- **Disable default capabilities**: Pass an empty `&ClientCapabilities{}` to
95+
disable all defaults, including roots.
96+
- **Disable listChanged notifications**: Set `ListChanged: false` on a
97+
capability to prevent the client from sending list-changed notifications
98+
when roots are added or removed.
99+
- **Configure elicitation modes**: Specify which elicitation modes (form, URL)
100+
the client supports.
101+
102+
```go
103+
// Configure elicitation modes and disable roots.
104+
client := mcp.NewClient(impl, &mcp.ClientOptions{
105+
Capabilities: &mcp.ClientCapabilities{
106+
Elicitation: &mcp.ElicitationCapabilities{
107+
Form: &mcp.FormElicitationCapabilities{},
108+
URL: &mcp.URLElicitationCapabilities{},
109+
},
110+
},
111+
ElicitationHandler: handler,
112+
})
113+
```
114+

internal/docs/rough_edges.src.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,12 @@ v2.
3535

3636
**Workaround**: use `ClientCapabilities.RootsV2`, which aligns with the
3737
semantics of other capability fields.
38+
39+
- Default capabilities should have been empty. Instead, servers default to
40+
advertising `logging`, and clients default to advertising `roots` with
41+
`listChanged: true`. This is confusing because a nil `Capabilities` field
42+
does not mean "no capabilities".
43+
44+
**Workaround**: to advertise no capabilities, set
45+
`ServerOptions.Capabilities` or `ClientOptions.Capabilities` to an empty
46+
`&ServerCapabilities{}` or `&ClientCapabilities{}` respectively.

internal/docs/server.src.md

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,53 @@ Call [`ClientSession.SetLevel`](https://pkg.go.dev/github.com/modelcontextprotoc
243243

244244
%include ../../mcp/server_example_test.go logging -
245245

246+
## Capabilities
247+
248+
Server capabilities are advertised to clients during the initialization
249+
handshake. By default, the SDK advertises only the `logging` capability.
250+
Additional capabilities are automatically added when features are registered
251+
(e.g., adding a tool adds the `tools` capability).
252+
253+
### Capability inference
254+
255+
When features such as tools, prompts, or resources are added to the server
256+
(e.g., via `Server.AddTool`), their capability is automatically inferred, with
257+
default value `{listChanged:true}`. Similarly, if the
258+
`ServerOptions.SubscribeHandler` or `ServerOptions.CompletionHandler` are set,
259+
the corresponding capability is added.
260+
261+
### Explicit capabilities
262+
263+
To explicitly declare capabilities, or to override the [default inferred
264+
capability](#capability-inference), set
265+
[`ServerOptions.Capabilities`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ServerOptions.Capabilities).
266+
This sets the default server capabilities, before any capabilities are added
267+
based on configured handlers. If a capability is already present as a field in
268+
`Capabilities`, adding a feature or handler will not change its configuration.
269+
270+
This allows you to:
271+
272+
- **Disable default capabilities**: Pass an empty `&ServerCapabilities{}` to
273+
disable all defaults, including logging.
274+
- **Disable listChanged notifications**: Set `ListChanged: false` on a
275+
capability to prevent the server from sending list-changed notifications
276+
when features are added or removed.
277+
- **Pre-declare capabilities**: Declare capabilities before features are
278+
registered, useful for servers that load features dynamically.
279+
280+
```go
281+
// Disable listChanged notifications for tools
282+
server := mcp.NewServer(impl, &mcp.ServerOptions{
283+
Capabilities: &mcp.ServerCapabilities{
284+
Logging: &mcp.LoggingCapabilities{},
285+
Tools: &mcp.ToolCapabilities{ListChanged: false},
286+
},
287+
})
288+
```
289+
290+
**Deprecated**: The `HasPrompts`, `HasResources`, and `HasTools` fields on
291+
`ServerOptions` are deprecated. Use `Capabilities` instead.
292+
246293
### Pagination
247294

248295
Server-side feature lists may be

0 commit comments

Comments
 (0)