mcp: add Extensions field to capabilities per SEP-2133 (#794)

This implements
[SEP-2133](https://modelcontextprotocol.io/community/seps/2133-extensions)
and resolves #777.

## Summary of changes

- Add `Extensions` field to `ServerCapabilities` and
`ClientCapabilities` structs per
[SEP-2133](https://modelcontextprotocol.io/community/seps/2133-extensions)
- Add `AddExtension` helper methods on both types that normalize nil
settings to empty maps.
- [The spec requires an object, not
null](https://modelcontextprotocol.io/community/seps/2133-extensions#negotiation:~:text=an%20empty%20object%20indicates%20no%20settings.)
- Include shallow-copy support via `maps.Clone` in the existing
`clone()` methods
  - also include shallow-copy support for `Experimental` field.
- Add comprehensive tests: unit tests for nil-safety, capability
preservation, and over-the-wire round-trip

## What's tested

- [x] `go test ./mcp/...` passes
- [x] Server conformance tests pass (30 scenarios, 40 assertions, 0
failures)
- [x] Client conformance tests match existing baseline (auth scenarios
are known failures)
This commit is contained in:
Yamamoto, Hirotaka 2026-02-18 00:10:07 +09:00 • committed by GitHub
commit 3dd262606e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -441,6 +441,25 @@ func TestServerCapabilities(t *testing.T) {
Logging: &LoggingCapabilities{},
},
},
{
name: "extensions preserved",
configureServer: func(s *Server) {},
serverOpts: func() ServerOptions {
caps := &ServerCapabilities{
Logging: &LoggingCapabilities{},
}
caps.AddExtension("io.example/ext1", map[string]any{"key": "value"})
caps.AddExtension("io.example/ext2", nil)
return ServerOptions{Capabilities: caps}
}(),
wantCapabilities: &ServerCapabilities{
Extensions: map[string]any{
"io.example/ext1": map[string]any{"key": "value"},
"io.example/ext2": map[string]any{},
},
Logging: &LoggingCapabilities{},
},
},
}
for _, tc := range testCases {
@ -927,6 +946,23 @@ func TestServerCapabilitiesOverWire(t *testing.T) {
Tools: &ToolCapabilities{ListChanged: true},
},
},
{
name: "Extensions over wire",
serverOpts: func() *ServerOptions {
caps := &ServerCapabilities{
Logging: &LoggingCapabilities{},
}
caps.AddExtension("io.example/ext", map[string]any{"key": "value"})
return &ServerOptions{Capabilities: caps}
}(),
configureServer: func(s *Server) {},
wantCapabilities: &ServerCapabilities{
Extensions: map[string]any{
"io.example/ext": map[string]any{"key": "value"},
},
Logging: &LoggingCapabilities{},
},
},
}
for _, tc := range testCases {