mcp: update return meta in DiscoverResult (SEP-2575) (#1097)

This PR implements the latest changes introduced by
https://github.com/modelcontextprotocol/modelcontextprotocol/pull/3002
This commit is contained in:
Guglielmo Colombo 2026-07-16 16:10:12 +02:00 • committed by GitHub
commit 5cb8339210
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
17 changed files with 210 additions and 68 deletions

View file

@ -1,7 +1,21 @@
server: [] # All tests pass!
server:
# The `server-stateless` scenario ships with the `@modelcontextprotocol/conformance@0.2.0-alpha.9`
# suite pinned by the workflow, which still enforces the pre-PR-3002
# (https://github.com/modelcontextprotocol/modelcontextprotocol/pull/3002) spec:
# - `clientInfo` in the per-request `_meta` is required (MUST).
# - `serverInfo` is a body field on `DiscoverResult`.
# PR #3002 relaxes `clientInfo` to SHOULD and moves `serverInfo` into every
# response's `_meta`. The Go SDK follows the updated spec, so the following
# checks in the `server-stateless` scenario fail against the pinned suite:
# - sep-2575-request-meta-invalid-missing-client-info
# - sep-2575-http-server-meta-invalid-400
# - sep-2575-server-implements-discover
# Remove this entry when the conformance suite is bumped to a release that
# incorporates PR #3002.
- server-stateless
client:
# OAuth mechanisms not yet implemented by the Go MCP SDK.
# OAuth mechanisms not implemented by the Go MCP SDK.
- auth/client-credentials-basic
- auth/client-credentials-jwt
- auth/enterprise-managed-authorization
@ -10,4 +24,6 @@ client:
# server/discover handler advertises "2026-07-28" but delegates every
# other method to a pinned @modelcontextprotocol/sdk that rejects that
# version at the HTTP layer.
# Remove this entry when the conformance suite is bumped to a release that
# fixes this issue.
- json-schema-ref-no-deref

View file

@ -4,6 +4,7 @@
1. [Lifecycle](#lifecycle)
1. [Discovery (`server/discover`)](#discovery-(server/discover))
1. [Per-request `_meta` keys](#per-request-meta-keys)
1. [Per-response `_meta` keys](#per-response-meta-keys)
1. [Subscriptions (`subscriptions/listen`)](#subscriptions-(subscriptions/listen))
1. [Transports](#transports)
1. [Stdio Transport](#stdio-transport)
@ -40,8 +41,10 @@ transparently based on the negotiated protocol version:
- A **stateless** model introduced in `2026-07-28` by
[SEP-2575](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2575),
in which there is no `initialize`/`notifications/initialized` handshake, and
each request carries its protocol version, client identity, and client
capabilities in `_meta`.
each request carries its protocol version and client capabilities in
`_meta`. Clients SHOULD also include their identity (`clientInfo`) on every
request, and servers SHOULD include their identity (`serverInfo`) on every
response.
In both models, the SDK exposes the same API:
@ -130,17 +133,28 @@ When the negotiated protocol version is `2026-07-28` or later, every request
carries these keys inside its `_meta` map (constants live in
[`mcp/protocol.go`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#pkg-constants)):
| Constant | Wire key | Type |
|---|---|---|
| `MetaKeyProtocolVersion` | `io.modelcontextprotocol/protocolVersion` | `string` |
| `MetaKeyClientInfo` | `io.modelcontextprotocol/clientInfo` | `*Implementation` |
| `MetaKeyClientCapabilities` | `io.modelcontextprotocol/clientCapabilities` | `*ClientCapabilities` |
| `MetaKeyLogLevel` | `io.modelcontextprotocol/logLevel` | `LoggingLevel` (deprecated by SEP-2577) |
| Constant | Wire key | Type | Required |
|---|---|---|---|
| `MetaKeyProtocolVersion` | `io.modelcontextprotocol/protocolVersion` | `string` | Yes |
| `MetaKeyClientCapabilities` | `io.modelcontextprotocol/clientCapabilities` | `*ClientCapabilities` | Yes |
| `MetaKeyClientInfo` | `io.modelcontextprotocol/clientInfo` | `*Implementation` | No |
| `MetaKeyLogLevel` | `io.modelcontextprotocol/logLevel` | `LoggingLevel` (deprecated by SEP-2577) | No |
The client populates these keys automatically on every outgoing request.
Server-side handlers can read them
through `ServerRequest[P].ProtocolVersion()`, `ServerRequest[P].ClientInfo()`,
and `ServerRequest[P].ClientCapabilities()`.
The client populates the required keys automatically on every outgoing
request, and populates `clientInfo` when configured with an `*Implementation`
(the default). Server-side handlers can read them through
`ServerRequest[P].ProtocolVersion()`, `ServerRequest[P].ClientInfo()`, and
`ServerRequest[P].ClientCapabilities()`.
### Per-response `_meta` keys
Under the same protocol version, servers SHOULD identify themselves on every
response. The SDK populates this
key automatically on every outgoing response:
| Constant | Wire key | Type | Required |
|---|---|---|---|
| `MetaKeyServerInfo` | `io.modelcontextprotocol/serverInfo` | `*Implementation` | No |
### Subscriptions (`subscriptions/listen`)

View file

@ -50,7 +50,7 @@ func ExampleLoggingTransport() {
}
// Output:
// read: {"jsonrpc":"2.0","id":1,"result":{"resultType":"complete","ttlMs":0,"cacheScope":"public","supportedVersions":["2026-07-28","2025-11-25","2025-06-18","2025-03-26","2024-11-05"],"capabilities":{"logging":{}},"serverInfo":{"name":"server","version":"v0.0.1"}}}
// read: {"jsonrpc":"2.0","id":1,"result":{"resultType":"complete","_meta":{"io.modelcontextprotocol/serverInfo":{"name":"server","version":"v0.0.1"}},"ttlMs":0,"cacheScope":"public","supportedVersions":["2026-07-28","2025-11-25","2025-06-18","2025-03-26","2024-11-05"],"capabilities":{"logging":{}}}}
// write: {"jsonrpc":"2.0","id":1,"method":"server/discover","params":{"_meta":{"io.modelcontextprotocol/clientCapabilities":{"roots":{"listChanged":true}},"io.modelcontextprotocol/clientInfo":{"name":"client","version":"v0.0.1"},"io.modelcontextprotocol/protocolVersion":"2026-07-28"}}}
}
```

View file

@ -17,8 +17,10 @@ transparently based on the negotiated protocol version:
- A **stateless** model introduced in `2026-07-28` by
[SEP-2575](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2575),
in which there is no `initialize`/`notifications/initialized` handshake, and
each request carries its protocol version, client identity, and client
capabilities in `_meta`.
each request carries its protocol version and client capabilities in
`_meta`. Clients SHOULD also include their identity (`clientInfo`) on every
request, and servers SHOULD include their identity (`serverInfo`) on every
response.
In both models, the SDK exposes the same API:
@ -76,17 +78,28 @@ When the negotiated protocol version is `2026-07-28` or later, every request
carries these keys inside its `_meta` map (constants live in
[`mcp/protocol.go`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#pkg-constants)):
| Constant | Wire key | Type |
|---|---|---|
| `MetaKeyProtocolVersion` | `io.modelcontextprotocol/protocolVersion` | `string` |
| `MetaKeyClientInfo` | `io.modelcontextprotocol/clientInfo` | `*Implementation` |
| `MetaKeyClientCapabilities` | `io.modelcontextprotocol/clientCapabilities` | `*ClientCapabilities` |
| `MetaKeyLogLevel` | `io.modelcontextprotocol/logLevel` | `LoggingLevel` (deprecated by SEP-2577) |
| Constant | Wire key | Type | Required |
|---|---|---|---|
| `MetaKeyProtocolVersion` | `io.modelcontextprotocol/protocolVersion` | `string` | Yes |
| `MetaKeyClientCapabilities` | `io.modelcontextprotocol/clientCapabilities` | `*ClientCapabilities` | Yes |
| `MetaKeyClientInfo` | `io.modelcontextprotocol/clientInfo` | `*Implementation` | No |
| `MetaKeyLogLevel` | `io.modelcontextprotocol/logLevel` | `LoggingLevel` (deprecated by SEP-2577) | No |
The client populates these keys automatically on every outgoing request.
Server-side handlers can read them
through `ServerRequest[P].ProtocolVersion()`, `ServerRequest[P].ClientInfo()`,
and `ServerRequest[P].ClientCapabilities()`.
The client populates the required keys automatically on every outgoing
request, and populates `clientInfo` when configured with an `*Implementation`
(the default). Server-side handlers can read them through
`ServerRequest[P].ProtocolVersion()`, `ServerRequest[P].ClientInfo()`, and
`ServerRequest[P].ClientCapabilities()`.
### Per-response `_meta` keys
Under the same protocol version, servers SHOULD identify themselves on every
response. The SDK populates this
key automatically on every outgoing response:
| Constant | Wire key | Type | Required |
|---|---|---|---|
| `MetaKeyServerInfo` | `io.modelcontextprotocol/serverInfo` | `*Implementation` | No |
### Subscriptions (`subscriptions/listen`)

View file

@ -443,11 +443,15 @@ func (c *Client) discover(ctx context.Context, cs *ClientSession) (*InitializeRe
}
}
var serverInfo *Implementation
if v, ok := decodeMetaValue[*Implementation](res.GetMeta(), MetaKeyServerInfo); ok {
serverInfo = v
}
return &InitializeResult{
Capabilities: res.Capabilities,
Instructions: res.Instructions,
ProtocolVersion: negotiated,
ServerInfo: res.ServerInfo,
ServerInfo: serverInfo,
}, nil
}
@ -509,9 +513,12 @@ func (cs *ClientSession) usesNewProtocol() bool {
return res != nil && res.ProtocolVersion >= protocolVersion20260728
}
// injectRequestMeta populates the SEP-2575 per-request `_meta` triple
// (protocolVersion, clientInfo, clientCapabilities) on the given outgoing
// request params. Keys already present in params.Meta are not overwritten.
// injectRequestMeta populates the SEP-2575 per-request `_meta` fields
// (protocolVersion, optional clientInfo, clientCapabilities) on the given
// outgoing request params. Keys already present in params.Meta are not
// overwritten. Per PR modelcontextprotocol/modelcontextprotocol#3002
// clientInfo is SHOULD (not MUST), and is omitted when the client has no
// [Implementation] configured.
func injectRequestMeta[T any, P interface {
*T
Params
@ -527,7 +534,7 @@ func injectRequestMeta[T any, P interface {
if _, ok := m[MetaKeyProtocolVersion]; !ok {
m[MetaKeyProtocolVersion] = res.ProtocolVersion
}
if _, ok := m[MetaKeyClientInfo]; !ok {
if _, ok := m[MetaKeyClientInfo]; !ok && cs.client.impl != nil {
m[MetaKeyClientInfo] = cs.client.impl
}
if _, ok := m[MetaKeyClientCapabilities]; !ok {

View file

@ -662,11 +662,13 @@ func TestClientConnectDiscover(t *testing.T) {
name: "discover success skips initialize",
discoverHandler: func() (Result, error) {
return &DiscoverResult{
Meta: Meta{
MetaKeyServerInfo: &Implementation{Name: "discoverServer", Version: "v1.0.0"},
},
SupportedVersions: []string{protocolVersion20260728},
Capabilities: &ServerCapabilities{
Tools: &ToolCapabilities{ListChanged: true},
},
ServerInfo: &Implementation{Name: "discoverServer", Version: "v1.0.0"},
}, nil
},
wantInitialize: false,
@ -695,9 +697,11 @@ func TestClientConnectDiscover(t *testing.T) {
name: "no overlapping supported version falls back to initialize",
discoverHandler: func() (Result, error) {
return &DiscoverResult{
Meta: Meta{
MetaKeyServerInfo: &Implementation{Name: "discoverServer", Version: "v1.0.0"},
},
SupportedVersions: []string{otherVersionsOnly},
Capabilities: &ServerCapabilities{},
ServerInfo: &Implementation{Name: "discoverServer", Version: "v1.0.0"},
}, nil
},
wantInitialize: true,
@ -885,9 +889,11 @@ func TestInMemory_E2E_DiscoverFallback_NoOverlap(t *testing.T) {
return func(ctx context.Context, method string, req Request) (Result, error) {
if method == methodDiscover {
return &DiscoverResult{
Meta: Meta{
MetaKeyServerInfo: &Implementation{Name: "vpre-like-server", Version: "v1"},
},
SupportedVersions: []string{protocolVersion20251125},
Capabilities: &ServerCapabilities{},
ServerInfo: &Implementation{Name: "vpre-like-server", Version: "v1"},
}, nil
}
return next(ctx, method, req)

View file

@ -224,4 +224,12 @@ func TestContentUnmarshalNilWithInvalidContent(t *testing.T) {
}
}
var ctrCmpOpts = []cmp.Option{cmpopts.IgnoreUnexported(mcp.CallToolResult{}, mcp.GetPromptResult{}, mcp.ReadResourceResult{})}
var ctrCmpOpts = []cmp.Option{
cmpopts.IgnoreUnexported(mcp.CallToolResult{}, mcp.GetPromptResult{}, mcp.ReadResourceResult{}),
// Server responses under the >= 2026-07-28 protocol carry an auto-populated
// [mcp.MetaKeyServerInfo] entry; tests that compare result bodies against
// hand-crafted expected values should ignore it.
cmpopts.IgnoreFields(mcp.CallToolResult{}, "Meta"),
cmpopts.IgnoreFields(mcp.GetPromptResult{}, "Meta"),
cmpopts.IgnoreFields(mcp.ReadResourceResult{}, "Meta"),
}

View file

@ -2475,7 +2475,15 @@ func TestSetErrorPreservesContent(t *testing.T) {
}
}
var ctrCmpOpts = []cmp.Option{cmpopts.IgnoreUnexported(CallToolResult{}, GetPromptResult{}, ReadResourceResult{})}
var ctrCmpOpts = []cmp.Option{
cmpopts.IgnoreUnexported(CallToolResult{}, GetPromptResult{}, ReadResourceResult{}),
// Server responses under the >= 2026-07-28 protocol carry an auto-populated
// [MetaKeyServerInfo] entry; tests that compare result bodies against
// hand-crafted expected values should ignore it.
cmpopts.IgnoreFields(CallToolResult{}, "Meta"),
cmpopts.IgnoreFields(GetPromptResult{}, "Meta"),
cmpopts.IgnoreFields(ReadResourceResult{}, "Meta"),
}
// runSubscriptionsListenTest exercises the SEP-2575 auto-listen flow end-to-end
// against the supplied transport pair. It captures every notification and the

View file

@ -1143,8 +1143,6 @@ type DiscoverResult struct {
SupportedVersions []string `json:"supportedVersions"`
// The server's capabilities.
Capabilities *ServerCapabilities `json:"capabilities"`
// Information about the server implementation.
ServerInfo *Implementation `json:"serverInfo"`
// Instructions describing how to use the server and its features.
Instructions string `json:"instructions,omitempty"`
}
@ -2365,6 +2363,8 @@ const (
MetaKeyProtocolVersion = "io.modelcontextprotocol/protocolVersion"
// MetaKeyClientInfo carries the client's [Implementation].
MetaKeyClientInfo = "io.modelcontextprotocol/clientInfo"
// MetaKeyServerInfo carries the server's [Implementation] on responses.
MetaKeyServerInfo = "io.modelcontextprotocol/serverInfo"
// MetaKeyClientCapabilities carries the client's [ClientCapabilities].
MetaKeyClientCapabilities = "io.modelcontextprotocol/clientCapabilities"
// MetaKeyLogLevel identifies the desired log level for the request.

View file

@ -888,17 +888,21 @@ func (s *Server) discover(_ context.Context, req *ServerRequest[*DiscoverParams]
if versions == nil {
versions = slices.Clone(supportedProtocolVersions)
}
// Read the request-scoped identity/capabilities before acquiring the
// session lock: these accessors may fall back to Session.InitializeParams
// (which also locks Session.mu), so calling them from inside updateState
// would self-deadlock.
init := &InitializeParams{
ProtocolVersion: req.ProtocolVersion(),
Capabilities: req.ClientCapabilities(),
ClientInfo: req.ClientInfo(),
}
req.Session.updateState(func(state *ServerSessionState) {
state.InitializeParams = &InitializeParams{
ProtocolVersion: req.ProtocolVersion(),
Capabilities: req.ClientCapabilities(),
ClientInfo: req.ClientInfo(),
}
state.InitializeParams = init
})
res := &DiscoverResult{
SupportedVersions: versions,
Capabilities: s.capabilities(),
ServerInfo: s.impl,
Instructions: s.opts.Instructions,
}
res.setDefaultCacheableValues()
@ -1924,10 +1928,32 @@ func (ss *ServerSession) handle(ctx context.Context, req *jsonrpc.Request) (any,
}
if validatedMeta.usesNewProtocol {
setCompleteResultType(res)
annotateServerInfo(res, ss.server.impl)
}
return res, nil
}
// annotateServerInfo sets [MetaKeyServerInfo] on the result's `_meta` unless
// it is already present. Per SEP-2575, servers should identify themselves in
// each result's `_meta`.
func annotateServerInfo(res Result, impl *Implementation) {
if res == nil || impl == nil {
return
}
if _, isEmpty := res.(*emptyResult); isEmpty {
return
}
m := res.GetMeta()
if m == nil {
m = map[string]any{}
}
if _, ok := m[MetaKeyServerInfo]; ok {
return
}
m[MetaKeyServerInfo] = impl
res.SetMeta(m)
}
// InitializeParams returns the InitializeParams provided during the client's
// initial connection.
func (ss *ServerSession) InitializeParams() *InitializeParams {

View file

@ -535,9 +535,10 @@ type validatedMeta struct {
// the >= 2026-07-28 protocol via the `_meta` field.
// If the request has no _meta, or no protocolVersion in _meta, it returns a non-nil
// validatedMeta with usesNewProtocol set to false, and a nil error.
// If the request has a protocolVersion in _meta it validates the presence of clientInfo
// and clientCapabilities in _meta. If either is missing or invalid, it returns nil and
// a non-nil error. Otherwise, it returns usesNewProtocol set to true and the populated
// If the request has a protocolVersion in _meta it validates the presence of
// clientCapabilities in _meta. If it is missing or invalid, it returns nil and
// a non-nil error. clientInfo is optional; if present but invalid, an error is
// returned. Otherwise, it returns usesNewProtocol set to true and the populated
// initializeParams.
func validateRequestMeta(req *jsonrpc.Request) (*validatedMeta, error) {
meta := extractRequestMeta(req.Params)
@ -548,11 +549,15 @@ func validateRequestMeta(req *jsonrpc.Request) (*validatedMeta, error) {
if !ok || protocolVersion < protocolVersion20260728 {
return &validatedMeta{usesNewProtocol: false, initializeParams: nil}, nil
}
clientInfo, ok := decodeMetaValue[*Implementation](meta, MetaKeyClientInfo)
if !ok {
return nil, &jsonrpc.Error{
Code: jsonrpc.CodeInvalidParams,
Message: fmt.Sprintf("missing or invalid _meta field %q", MetaKeyClientInfo),
var clientInfo *Implementation
if _, present := meta[MetaKeyClientInfo]; present {
var ok bool
clientInfo, ok = decodeMetaValue[*Implementation](meta, MetaKeyClientInfo)
if !ok {
return nil, &jsonrpc.Error{
Code: jsonrpc.CodeInvalidParams,
Message: fmt.Sprintf("invalid _meta field %q", MetaKeyClientInfo),
}
}
}
capabilities, ok := decodeMetaValue[*clientCapabilitiesV2](meta, MetaKeyClientCapabilities)

View file

@ -67,6 +67,19 @@ func TestValidateRequestMeta(t *testing.T) {
},
"name": "x",
},
wantUsesNew: true,
},
{
name: "new protocol invalid clientInfo",
method: methodCallTool,
params: map[string]any{
"_meta": map[string]any{
MetaKeyProtocolVersion: protocolVersion20260728,
MetaKeyClientInfo: "not an object",
MetaKeyClientCapabilities: map[string]any{},
},
"name": "x",
},
wantUsesNew: false,
wantErrContains: MetaKeyClientInfo,
},

View file

@ -1265,11 +1265,13 @@ func TestStreamableClientOAuth_RetrieveError(t *testing.T) {
// discoverResult is the canned successful DiscoverResult returned by
// fakeStreamableServer setups in the tests below.
var discoverResult = &DiscoverResult{
Meta: Meta{
MetaKeyServerInfo: &Implementation{Name: "discoverServer", Version: "v1.0.0"},
},
SupportedVersions: []string{protocolVersion20260728},
Capabilities: &ServerCapabilities{
Tools: &ToolCapabilities{ListChanged: true},
},
ServerInfo: &Implementation{Name: "discoverServer", Version: "v1.0.0"},
Instructions: "test discover",
}

View file

@ -794,6 +794,15 @@ func completeCallToolResult() *CallToolResult {
return r
}
// completeCallToolResultWithServerInfo returns a completeCallToolResult
// annotated with the auto-populated [MetaKeyServerInfo] entry that servers
// add to every new-protocol response.
func completeCallToolResultWithServerInfo(impl *Implementation) *CallToolResult {
r := completeCallToolResult()
r.Meta = Meta{MetaKeyServerInfo: impl}
return r
}
func resp(id int64, result any, err error) *jsonrpc.Response {
return &jsonrpc.Response{
ID: jsonrpc2.Int64ID(id),
@ -1958,6 +1967,7 @@ func TestStreamableMcpHeaderValidation(t *testing.T) {
MetaKeyClientInfo: map[string]any{"name": "testClient", "version": "v1.0.0"},
MetaKeyClientCapabilities: map[string]any{},
}
serverImpl := &Implementation{Name: "testServer", Version: "v1.0.0"}
testStreamableHandler(t, handler, []streamableRequest{
{
@ -1969,7 +1979,7 @@ func TestStreamableMcpHeaderValidation(t *testing.T) {
},
messages: []jsonrpc.Message{req(2, "tools/call", &CallToolParams{Meta: testMeta, Name: "my-tool"})},
wantStatusCode: http.StatusOK,
wantMessages: []jsonrpc.Message{resp(2, completeCallToolResult(), nil)},
wantMessages: []jsonrpc.Message{resp(2, completeCallToolResultWithServerInfo(serverImpl), nil)},
},
{
method: "POST",
@ -2013,7 +2023,7 @@ func TestStreamableMcpHeaderValidation(t *testing.T) {
},
messages: []jsonrpc.Message{req(6, "tools/call", &CallToolParams{Meta: testMeta, Name: "my-tool"})},
wantStatusCode: http.StatusOK,
wantMessages: []jsonrpc.Message{resp(6, completeCallToolResult(), nil)},
wantMessages: []jsonrpc.Message{resp(6, completeCallToolResultWithServerInfo(serverImpl), nil)},
},
{
method: "POST",
@ -2029,7 +2039,7 @@ func TestStreamableMcpHeaderValidation(t *testing.T) {
Arguments: map[string]any{"region": "us-west1", "query": "SELECT 1"},
})},
wantStatusCode: http.StatusOK,
wantMessages: []jsonrpc.Message{resp(7, completeCallToolResult(), nil)},
wantMessages: []jsonrpc.Message{resp(7, completeCallToolResultWithServerInfo(serverImpl), nil)},
},
{
method: "POST",

View file

@ -1,7 +1,7 @@
The client sends a discover request
carrying the required per-request _meta triple (protocolVersion, clientInfo,
clientCapabilities), and the server replies with the protocol versions it
supports, its capabilities, and its identity.
The client sends a discover request carrying the per-request _meta
(protocolVersion, clientInfo, clientCapabilities), and the server
replies with the protocol versions it supports, its capabilities, and its
identity via `_meta.io.modelcontextprotocol/serverInfo`.
-- client --
{
@ -22,6 +22,12 @@ supports, its capabilities, and its identity.
"id": 1,
"result": {
"resultType": "complete",
"_meta": {
"io.modelcontextprotocol/serverInfo": {
"name": "testServer",
"version": "v1.0.0"
}
},
"ttlMs": 0,
"cacheScope": "public",
"supportedVersions": [
@ -33,10 +39,6 @@ supports, its capabilities, and its identity.
],
"capabilities": {
"logging": {}
},
"serverInfo": {
"name": "testServer",
"version": "v1.0.0"
}
}
}

View file

@ -45,6 +45,12 @@ confirmThenGreet
"jsonrpc": "2.0",
"id": 1,
"result": {
"_meta": {
"io.modelcontextprotocol/serverInfo": {
"name": "testServer",
"version": "v1.0.0"
}
},
"content": null,
"requestState": "step=1",
"resultType": "input_required",
@ -71,6 +77,12 @@ confirmThenGreet
"jsonrpc": "2.0",
"id": 2,
"result": {
"_meta": {
"io.modelcontextprotocol/serverInfo": {
"name": "testServer",
"version": "v1.0.0"
}
},
"content": [
{
"type": "text",

View file

@ -42,7 +42,7 @@ func ExampleLoggingTransport() {
}
// Output:
// read: {"jsonrpc":"2.0","id":1,"result":{"resultType":"complete","ttlMs":0,"cacheScope":"public","supportedVersions":["2026-07-28","2025-11-25","2025-06-18","2025-03-26","2024-11-05"],"capabilities":{"logging":{}},"serverInfo":{"name":"server","version":"v0.0.1"}}}
// read: {"jsonrpc":"2.0","id":1,"result":{"resultType":"complete","_meta":{"io.modelcontextprotocol/serverInfo":{"name":"server","version":"v0.0.1"}},"ttlMs":0,"cacheScope":"public","supportedVersions":["2026-07-28","2025-11-25","2025-06-18","2025-03-26","2024-11-05"],"capabilities":{"logging":{}}}}
// write: {"jsonrpc":"2.0","id":1,"method":"server/discover","params":{"_meta":{"io.modelcontextprotocol/clientCapabilities":{"roots":{"listChanged":true}},"io.modelcontextprotocol/clientInfo":{"name":"client","version":"v0.0.1"},"io.modelcontextprotocol/protocolVersion":"2026-07-28"}}}
}