mcp: add documentation for new protocol version (#1019)

Add documentation for new protocol version in the `internal/docs`
This commit is contained in:
Guglielmo Colombo 2026-06-23 17:07:38 +02:00 • committed by GitHub
commit b9e6fc5a66
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 719 additions and 36 deletions

View file

@ -34,11 +34,12 @@ contains feature documentation, mapping the MCP spec to the packages above.
The following table shows which versions of the Go SDK support which versions of the MCP specification: The following table shows which versions of the Go SDK support which versions of the MCP specification:
| SDK Version | Latest MCP Spec | All Supported MCP Specs | | SDK Version | Latest MCP Spec | All Supported MCP Specs |
|-----------------|-------------------|----------------------------------------------------| |-----------------|-------------------|------------------------------------------------------------------|
| v1.4.0+ | 2025-11-25\* | 2025-11-25\*, 2025-06-18, 2025-03-26, 2024-11-05 | | v1.7.0+ | 2026-07-28 | 2026-07-28, 2025-11-25\*, 2025-06-18, 2025-03-26, 2024-11-05 |
| v1.2.0 - v1.3.1 | 2025-11-25\*\* | 2025-11-25\*\*, 2025-06-18, 2025-03-26, 2024-11-05 | | v1.4.0 - v1.6.1 | 2025-11-25\* | 2025-11-25\*, 2025-06-18, 2025-03-26, 2024-11-05 |
| v1.0.0 - v1.1.0 | 2025-06-18 | 2025-06-18, 2025-03-26, 2024-11-05 | | v1.2.0 - v1.3.1 | 2025-11-25\*\* | 2025-11-25\*\*, 2025-06-18, 2025-03-26, 2024-11-05 |
| v1.0.0 - v1.1.0 | 2025-06-18 | 2025-06-18, 2025-03-26, 2024-11-05 |
\* Client side OAuth has experimental support. \* Client side OAuth has experimental support.

View file

@ -4,9 +4,11 @@
1. [Roots](#roots) 1. [Roots](#roots)
1. [Sampling](#sampling) 1. [Sampling](#sampling)
1. [Elicitation](#elicitation) 1. [Elicitation](#elicitation)
1. [Multi Round-Trip Requests (MRTR)](#multi-round-trip-requests-(mrtr))
1. [Capabilities](#capabilities) 1. [Capabilities](#capabilities)
1. [Capability inference](#capability-inference) 1. [Capability inference](#capability-inference)
1. [Explicit capabilities](#explicit-capabilities) 1. [Explicit capabilities](#explicit-capabilities)
1. [Extensions](#extensions)
## Roots ## Roots
@ -34,6 +36,10 @@ client, a call to `AddRoot` or `RemoveRoots` will result in a
[`ServerSession.ListRoots`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ServerSession.ListRoots) [`ServerSession.ListRoots`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ServerSession.ListRoots)
method. To receive notifications about root changes, set method. To receive notifications about root changes, set
[`ServerOptions.RootsListChangedHandler`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ServerOptions.RootsListChangedHandler). [`ServerOptions.RootsListChangedHandler`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ServerOptions.RootsListChangedHandler).
For protocol versions `2026-07-28` and later, `ListRoots` requests are
delivered via the
[Multi Round-Trip Requests](protocol.md#multi-round-trip-requests-mrtr)
pattern.
```go ```go
func Example_roots() { func Example_roots() {
@ -102,6 +108,11 @@ This function is invoked whenever the server requests sampling.
**Server-side**: To use sampling from the server, call **Server-side**: To use sampling from the server, call
[`ServerSession.CreateMessage`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ServerSession.CreateMessage). [`ServerSession.CreateMessage`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ServerSession.CreateMessage).
For protocol versions `2026-07-28` and later, sampling requests are
delivered via the
[Multi Round-Trip Requests](protocol.md#multi-round-trip-requests-mrtr)
pattern.
```go ```go
func Example_sampling() { func Example_sampling() {
ctx := context.Background() ctx := context.Background()
@ -154,6 +165,11 @@ you must declare that capability explicitly (see [Capabilities](#capabilities))
**Server-side**: To use elicitation from the server, call **Server-side**: To use elicitation from the server, call
[`ServerSession.Elicit`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ServerSession.Elicit). [`ServerSession.Elicit`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ServerSession.Elicit).
For protocol versions `2026-07-28` and later, elicitation requests are
delivered via the
[Multi Round-Trip Requests](protocol.md#multi-round-trip-requests-mrtr)
pattern.
```go ```go
func Example_elicitation() { func Example_elicitation() {
ctx := context.Background() ctx := context.Background()
@ -191,6 +207,37 @@ func Example_elicitation() {
} }
``` ```
## Multi Round-Trip Requests (MRTR)
[SEP-2322](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2322)
introduces the MRTR pattern: server-to-client requests for sampling,
elicitation, and roots are no longer issued as fresh JSON-RPC requests but
are carried inside the in-flight reply of a `tools/call`, `prompts/get`, or
`resources/read`. The client must respond by retrying the original request
with the produced responses.
The SDK installs `clientMultiRoundTripMiddleware` for every client by
default. The middleware:
1. Inspects each `tools/call`/`prompts/get`/`resources/read` reply.
2. If the result's `NeedsInput()` is true, fans out the `InputRequests` map
concurrently, calling the configured handler for each (`elicit`,
`createMessage`/`createMessageWithTools`, or `listRoots`).
3. Threads the server-supplied opaque `RequestState` back unchanged.
4. Retries the original request with the responses set, repeating until the
result no longer needs input.
The middleware is enabled by default. To opt out, set
[`ClientOptions.MultiRoundTrip.Disabled = true`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#MultiRoundTripOptions);
the client will then surface `InputRequiredResult` values directly to the
caller and your code must fulfil the requests manually.
For legacy (`<= 2025-11-25`) servers, the SDK transparently sends server
requests on the legacy server-initiated channel; the MRTR machinery is a
no-op in that direction. For legacy clients talking to MRTR-style servers,
the server SDK applies the inverse compatibility shim — see the
[server-side documentation](server.md#multi-round-trip-requests-mrtr).
## Capabilities ## Capabilities
Client capabilities are advertised to servers during the initialization Client capabilities are advertised to servers during the initialization
@ -247,3 +294,11 @@ client := mcp.NewClient(impl, &mcp.ClientOptions{
}) })
``` ```
### Extensions
[SEP-2133](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2133)
adds an `extensions` map to `ClientCapabilities` and `ServerCapabilities` so
that optional capabilities outside the core protocol can be declared on the
wire. Keys are namespaced as `"{vendor-prefix}/{extension-name}"`; values
are per-extension settings objects.

View file

@ -2,6 +2,8 @@
# Support for the MCP base protocol # Support for the MCP base protocol
1. [Lifecycle](#lifecycle) 1. [Lifecycle](#lifecycle)
1. [Discovery (`server/discover`)](#discovery-(server/discover))
1. [Per-request `_meta` keys](#per-request-meta-keys)
1. [Transports](#transports) 1. [Transports](#transports)
1. [Stdio Transport](#stdio-transport) 1. [Stdio Transport](#stdio-transport)
1. [Streamable Transport](#streamable-transport) 1. [Streamable Transport](#streamable-transport)
@ -20,20 +22,27 @@
1. [Cancellation](#cancellation) 1. [Cancellation](#cancellation)
1. [Ping](#ping) 1. [Ping](#ping)
1. [Progress](#progress) 1. [Progress](#progress)
1. [Error codes](#error-codes)
## Lifecycle ## Lifecycle
The SDK provides an API for defining both MCP clients and servers, and The SDK provides an API for defining both MCP clients and servers, and
connecting them over various transports. When a client and server are connecting them over various transports. When a client and server are
connected, it creates a logical session, which follows the MCP spec's connected, it creates a logical session.
[lifecycle](https://modelcontextprotocol.io/specification/2025-06-18/basic/lifecycle).
In this SDK, both a The MCP specification defines two lifecycle models, and the SDK supports both
[`Client`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#Client) transparently based on the negotiated protocol version:
and
[`Server`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#Server) - The **legacy `initialize` handshake**
can handle multiple peers. Every time a new peer is connected, it creates a new ([lifecycle](https://modelcontextprotocol.io/specification/2025-06-18/basic/lifecycle))
session. used by protocol versions through `2025-11-25`.
- 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`.
In both models, the SDK exposes the same API:
- A `Client` is a logical MCP client, configured with various - A `Client` is a logical MCP client, configured with various
[`ClientOptions`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ClientOptions). [`ClientOptions`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ClientOptions).
@ -49,11 +58,16 @@ session.
[`Server.Connect`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#Server.Connect), [`Server.Connect`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#Server.Connect),
it creates a it creates a
[`ServerSession`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ServerSession). [`ServerSession`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ServerSession).
This session is not initialized until the client sends the
`notifications/initialized` message. Use `ServerOptions.InitializedHandler` In the legacy model, the server session is not considered initialized until
to listen for this event, or just use the session through various feature the client sends the `notifications/initialized` message. Use
handlers (such as a `ToolHandler`). Requests to the server are rejected until `ServerOptions.InitializedHandler` to listen for this event, or just use the
the client has initialized the session. session through various feature handlers (such as a `ToolHandler`). Requests
to the server are rejected until the client has initialized the session.
In the stateless model (`2026-07-28`+), there is no handshake. The server
processes the first request the moment it arrives, validates the per-request
`_meta` fields.
Both `ClientSession` and `ServerSession` have a `Close` method to terminate the Both `ClientSession` and `ServerSession` have a `Close` method to terminate the
session, and a `Wait` method to await session termination by the peer. Typically, session, and a `Wait` method to await session termination by the peer. Typically,
@ -98,6 +112,41 @@ func Example_lifecycle() {
} }
``` ```
### Discovery (`server/discover`)
Introduced in `2026-07-28` by
[SEP-2575](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2575),
the `server/discover` RPC lets a client discover a server's supported
protocol versions, capabilities, and identity before issuing any other
request. Servers implementing `2026-07-28` MUST implement it.
- **Server**: `Server.Connect` registers the
`server/discover` handler automatically; the response is computed from the
server's static configuration (capabilities, server info, instructions) and
the transport-filtered list of supported protocol versions.
- **Client**: `Client.Connect` calls `server/discover` first and
uses the result to negotiate a mutually supported version. If discovery
fails or the server does not support the latest version, the client falls back to the
legacy `initialize` handshake.
### Per-request `_meta` keys
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) |
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()`.
## Transports ## Transports
A A
@ -188,6 +237,39 @@ client, err := mcp.Connect(ctx, transport, &mcp.ClientOptions{...})
The `StreamableClientTransport` handles the HTTP requests and communicates with The `StreamableClientTransport` handles the HTTP requests and communicates with
the server using the streamable transport protocol. the server using the streamable transport protocol.
#### HTTP Headers
[SEP-2243](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2243)
standardises a small set of MCP-specific HTTP headers, sent and validated by
the SDK only for sessions negotiated on protocol version `2026-07-28` or
later.
| Header | Direction | Purpose |
|---|---|---|
| `Mcp-Protocol-Version` | request | Mirrors `_meta.io.modelcontextprotocol/protocolVersion` from the body |
| `Mcp-Session-Id` | request/response | Logical session identifier (removed in stateless mode) |
| `Mcp-Method` | request | Mirrors the JSON-RPC `method` field; mismatch ⇒ `-32020` |
| `Mcp-Name` | request | Mirrors the request's principal name (`tools/call.params.name`, `prompts/get.params.name`, `resources/read.params.uri`); mismatch ⇒ `-32020` |
| `Mcp-Param-{Header}` | request | Per-tool parameter passthrough; see below |
The header-name set is exhaustive: for protocol versions earlier than
`2026-07-28`, only `Mcp-Protocol-Version` and `Mcp-Session-Id` are recognised.
**Body↔header mirroring.** When `Mcp-Method` or `Mcp-Name` is present but
does not match the JSON-RPC body, the server returns
[`CodeHeaderMismatch`](#error-codes) (`-32020`). The same applies to a
mismatch between `Mcp-Protocol-Version` and the body's
`_meta.io.modelcontextprotocol/protocolVersion`.
**`Mcp-Param-*` passthrough.** A tool may annotate properties of its
`InputSchema` with `x-mcp-header: "<HeaderName>"`. When a client invokes that
tool over HTTP, the SDK serializes the matching argument(s) as
`Mcp-Param-<HeaderName>` request headers (using `=?base64?...?=` encoding for
non-ASCII values). On the server, the headers are validated against the body
and either accepted or rejected with `-32020`. Properties so annotated must
be typed `string`, `integer`, or `boolean`; tools that fail validation at
registration time are silently dropped from `tools/list`.
#### Resumability and Redelivery #### Resumability and Redelivery
By default, the streamable server does not support [resumability or By default, the streamable server does not support [resumability or
@ -201,6 +283,13 @@ value. The SDK provides a `MemoryEventStore` for testing or simple use cases;
for production use it is generally advisable to use a more sophisticated for production use it is generally advisable to use a more sophisticated
implementation. implementation.
> **Note**: [SEP-2575](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2575)
> removes SSE stream resumability (`Last-Event-ID`, SSE event IDs) for protocol
> version `2026-07-28`. The SDK preserves the `EventStore` and `Last-Event-ID`
> code paths for backward compatibility with `2025-11-25` and earlier; on
> `2026-07-28` sessions, a broken response stream loses the in-flight request
> and the client must re-issue it as a new request with a new ID.
#### Stateless Mode #### Stateless Mode
The streamable server supports a _stateless mode_ by setting The streamable server supports a _stateless mode_ by setting
@ -219,6 +308,10 @@ to see the logical session
> modelcontextprotocol/modelcontextprotocol#1372, or > modelcontextprotocol/modelcontextprotocol#1372, or
> modelcontextprotocol/modelcontextprotocol#1442 for potential refinements. > modelcontextprotocol/modelcontextprotocol#1442 for potential refinements.
> **Required for `2026-07-28`**: the streamable HTTP transport accepts
> requests at protocol version `2026-07-28` **only** when `Stateless = true`.
> Requests at that version against a non-stateless handler are rejected.
_See [examples/server/distributed](https://github.com/modelcontextprotocol/go-sdk/blob/main/examples/server/distributed/main.go) for _See [examples/server/distributed](https://github.com/modelcontextprotocol/go-sdk/blob/main/examples/server/distributed/main.go) for
an example using stateless mode to implement a server distributed across an example using stateless mode to implement a server distributed across
multiple processes._ multiple processes._
@ -597,6 +690,13 @@ session if the ping fails, set
or or
[`ServerOptions.KeepAlive`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ServerOptions.KeepAlive). [`ServerOptions.KeepAlive`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ServerOptions.KeepAlive).
> **Note**: `ping` is removed from the protocol as of `2026-07-28` by
> [SEP-2575](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2575).
> The SDK preserves the API for backward compatibility with legacy clients;
> when both peers negotiate `2026-07-28`, the server returns
> `MethodNotFound` (`-32601`) for `ping` and `KeepAlive` should not be
> enabled.
### Progress ### Progress
[Progress](https://modelcontextprotocol.io/specification/2025-06-18/basic/utilities/progress) [Progress](https://modelcontextprotocol.io/specification/2025-06-18/basic/utilities/progress)
@ -658,3 +758,22 @@ func Example_progress() {
} }
``` ```
### Error codes
The SDK uses the standard JSON-RPC base codes (parse error `-32700`,
invalid request `-32600`, method not found `-32601`, invalid params
`-32602`, internal error `-32603`) plus the following MCP-specific codes:
| Constant | Code | Meaning |
|---|---|---|
| [`CodeHeaderMismatch`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#CodeHeaderMismatch) | `-32020` | An MCP HTTP header (`Mcp-Method`, `Mcp-Name`, `Mcp-Protocol-Version`, or `Mcp-Param-*`) does not match the JSON-RPC body |
| [`CodeMissingRequiredClientCapabilities`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#CodeMissingRequiredClientCapabilities) | `-32021` | Server requires client capabilities the client did not declare |
| [`CodeUnsupportedProtocolVersion`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#CodeUnsupportedProtocolVersion) | `-32022` | Requested protocol version not supported. Data: `UnsupportedProtocolVersionData{Supported []string, Requested string}` |
| [`CodeResourceNotFound`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#CodeResourceNotFound) | `-32602` | Resource URI not found (variable; was `-32002` before SEP-2164) |
The error code allocation policy defined in `2026-07-28`
([SEP-2575](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2575))
partitions the JSON-RPC server-error range:
- `-32000` to `-32019`: implementation-defined; existing SDK usage is grandfathered.
- `-32020` to `-32099`: reserved for the MCP specification.

View file

@ -4,12 +4,17 @@
1. [Prompts](#prompts) 1. [Prompts](#prompts)
1. [Resources](#resources) 1. [Resources](#resources)
1. [Tools](#tools) 1. [Tools](#tools)
1. [Multi Round-Trip Requests (MRTR)](#multi-round-trip-requests-(mrtr))
1. [Talking to legacy clients](#talking-to-legacy-clients)
1. [Example](#example)
1. [Cacheable list results](#cacheable-list-results)
1. [Utilities](#utilities) 1. [Utilities](#utilities)
1. [Completion](#completion) 1. [Completion](#completion)
1. [Logging](#logging) 1. [Logging](#logging)
1. [Capabilities](#capabilities) 1. [Capabilities](#capabilities)
1. [Capability inference](#capability-inference) 1. [Capability inference](#capability-inference)
1. [Explicit capabilities](#explicit-capabilities) 1. [Explicit capabilities](#explicit-capabilities)
1. [Extensions](#extensions)
1. [Pagination](#pagination) 1. [Pagination](#pagination)
## Prompts ## Prompts
@ -424,6 +429,162 @@ func handleRequest(w http.ResponseWriter, r *http.Request) {
} }
``` ```
## Multi Round-Trip Requests (MRTR)
[SEP-2322](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2322)
defines a new pattern for server-to-client requests (sampling, elicitation,
roots). Instead of issuing a fresh JSON-RPC request mid-flight, the server
returns an `InputRequiredResult` from its in-flight handler — the
`InputRequests` field of `CallToolResult`, `GetPromptResult`, or
`ReadResourceResult` carries the requests for additional information. The
client responds by retrying the original call with `InputResponses` set.
The SDK supports this pattern from both sides without requiring callers to
choose:
- **Returning input requests from a handler.** Set `InputRequests` on the
result you return.
Leave `Content` / `StructuredContent` empty — returning
both at once is a server bug and the SDK returns `-32603 InternalError`.
- **Calling the legacy APIs.** `ServerSession.Elicit`,
`ServerSession.CreateMessage(WithTools)`, and `ServerSession.ListRoots`
remain available and work for both new and legacy clients.
### Talking to legacy clients
The server installs `serverMultiRoundTripMiddleware` automatically. For
clients on a protocol version earlier than `2026-07-28`, the middleware
intercepts any `InputRequiredResult` your handler returns, fulfils each
input request itself by calling the legacy server-initiated APIs
(`Elicit`, `CreateMessage`, `ListRoots`), and re-invokes your handler
exactly once with the responses already populated. This means a handler
written in the MRTR style works against both old and new clients without
code changes.
### Example
The following example shows a "greet" tool whose handler asks the user
for their name via elicitation before producing the final greeting. The
handler runs twice — once to issue the elicitation, once to consume the
response — but the client call site sees a single `CallTool` returning the
final result, because the SDK's MRTR middleware handles the round trip on
either side of the wire (depending on the negotiated protocol version).
```go
// Example_mrtr demonstrates the [Multi Round-Trip Requests] pattern
// (SEP-2322). A tool handler signals "I need more information from the user"
// by returning a [mcp.CallToolResult] whose `InputRequests` field carries the
// requests for the additional information. Each request can be an
// [mcp.ElicitParams] (ask the user a question),
// [mcp.CreateMessageParams] (sample from the client's LLM), or
// [mcp.ListRootsParams] (list the client's roots).
//
// On protocol version `2026-07-28` and later, the client's
// `clientMultiRoundTripMiddleware` fulfils each input request from the
// configured handler and retries the original call transparently. On earlier
// protocol versions, the server's `serverMultiRoundTripMiddleware` performs
// the equivalent dance from the server side by calling the legacy
// server-to-client API (`ServerSession.Elicit`, `CreateMessage`, or
// `ListRoots`) and re-invoking the handler with the response. Either way,
// the user-facing client call site sees only the final result.
//
// [Multi Round-Trip Requests]: https://modelcontextprotocol.io/specification/draft/basic/patterns#multi-round-trip-requests
func Example_mrtr() {
ctx := context.Background()
// Server: a "greet" tool that asks the user for their name before
// returning a greeting. The handler runs twice per logical call:
// once to issue the elicitation, once to consume the response.
s := mcp.NewServer(&mcp.Implementation{Name: "server", Version: "v0.0.1"}, nil)
mcp.AddTool(s, &mcp.Tool{Name: "greet"}, func(_ context.Context, req *mcp.CallToolRequest, _ struct{}) (*mcp.CallToolResult, any, error) {
if len(req.Params.InputResponses) == 0 {
// First call: ask the user for their name. The map key
// ("user_name") is a label the handler chooses; the client must
// echo it back in InputResponses. The wire-level method name
// ("elicitation/create") is derived from the value's Go type.
return &mcp.CallToolResult{
InputRequests: mcp.InputRequestMap{
"user_name": &mcp.ElicitParams{
Message: "What's your name?",
RequestedSchema: &jsonschema.Schema{
Type: "object",
Properties: map[string]*jsonschema.Schema{
"name": {Type: "string"},
},
},
},
},
// RequestState is an opaque token the client echoes back on
// the retry, letting the handler resume its work without
// per-session storage.
RequestState: "step=1",
}, nil, nil
}
// Retry: read the elicitation response and produce the final greeting.
name := req.Params.InputResponses["user_name"].(*mcp.ElicitResult).Content["name"].(string)
return &mcp.CallToolResult{
Content: []mcp.Content{&mcp.TextContent{Text: "Hello " + name}},
}, nil, nil
})
// Client: declares an elicitation handler. The SDK's MRTR middleware
// uses it to fulfil any input request the tool handler returns.
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{"name": "Ada"}}, nil
},
})
ct, st := mcp.NewInMemoryTransports()
if _, err := s.Connect(ctx, st, nil); err != nil {
log.Fatal(err)
}
cs, err := c.Connect(ctx, ct, nil)
if err != nil {
log.Fatal(err)
}
defer cs.Close()
// Single call site. The MRTR round trip is invisible to the caller.
res, err := cs.CallTool(ctx, &mcp.CallToolParams{Name: "greet"})
if err != nil {
log.Fatal(err)
}
fmt.Println(res.Content[0].(*mcp.TextContent).Text)
}
```
## Cacheable list results
[SEP-2549](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2549)
adds `ttlMs` and `cacheScope` fields to the results of `tools/list`,
`prompts/list`, `resources/list`, `resources/templates/list`, and
`resources/read`. Both fields complement existing list
results: clients use `ttlMs` as a freshness hint to reduce polling,
and `cacheScope` (`"public"` or `"private"`) controls whether shared
intermediaries may cache the response.
**Server-side defaults.** After paginating, the SDK sets `CacheScope = "public"`
and leaves `TTLMs = 0` (which the client cache treats as "immediately
stale"). A handler that wants its responses cached must set `TTLMs`
explicitly on the returned result.
```go
mcp.AddTool(server, &mcp.Tool{Name: "expensive"}, func(...) (*mcp.CallToolResult, any, error) {
// ...
})
// Override the default for tools/list:
server.AddSendingMiddleware(func(next mcp.MethodHandler) mcp.MethodHandler {
return func(ctx context.Context, method string, req mcp.Request) (mcp.Result, error) {
res, err := next(ctx, method, req)
if lr, ok := res.(*mcp.ListToolsResult); ok {
lr.TTLMs = 30_000 // 30s cache freshness hint
}
return res, err
}
})
```
## Utilities ## Utilities
### Completion ### Completion
@ -613,6 +774,14 @@ server := mcp.NewServer(impl, &mcp.ServerOptions{
**Deprecated**: The `HasPrompts`, `HasResources`, and `HasTools` fields on **Deprecated**: The `HasPrompts`, `HasResources`, and `HasTools` fields on
`ServerOptions` are deprecated. Use `Capabilities` instead. `ServerOptions` are deprecated. Use `Capabilities` instead.
### Extensions
[SEP-2133](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2133)
adds an `extensions` map to `ServerCapabilities` so that optional
capabilities outside the core protocol can be declared on the wire. Keys
are namespaced as `"{vendor-prefix}/{extension-name}"`; values are
per-extension settings objects.
### Pagination ### Pagination
Server-side feature lists may be Server-side feature lists may be

View file

@ -28,6 +28,10 @@ client, a call to `AddRoot` or `RemoveRoots` will result in a
[`ServerSession.ListRoots`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ServerSession.ListRoots) [`ServerSession.ListRoots`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ServerSession.ListRoots)
method. To receive notifications about root changes, set method. To receive notifications about root changes, set
[`ServerOptions.RootsListChangedHandler`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ServerOptions.RootsListChangedHandler). [`ServerOptions.RootsListChangedHandler`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ServerOptions.RootsListChangedHandler).
For protocol versions `2026-07-28` and later, `ListRoots` requests are
delivered via the
[Multi Round-Trip Requests](protocol.md#multi-round-trip-requests-mrtr)
pattern.
%include ../../mcp/client_example_test.go roots - %include ../../mcp/client_example_test.go roots -
@ -51,6 +55,11 @@ This function is invoked whenever the server requests sampling.
**Server-side**: To use sampling from the server, call **Server-side**: To use sampling from the server, call
[`ServerSession.CreateMessage`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ServerSession.CreateMessage). [`ServerSession.CreateMessage`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ServerSession.CreateMessage).
For protocol versions `2026-07-28` and later, sampling requests are
delivered via the
[Multi Round-Trip Requests](protocol.md#multi-round-trip-requests-mrtr)
pattern.
%include ../../mcp/client_example_test.go sampling - %include ../../mcp/client_example_test.go sampling -
## Elicitation ## Elicitation
@ -68,8 +77,44 @@ you must declare that capability explicitly (see [Capabilities](#capabilities))
**Server-side**: To use elicitation from the server, call **Server-side**: To use elicitation from the server, call
[`ServerSession.Elicit`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ServerSession.Elicit). [`ServerSession.Elicit`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ServerSession.Elicit).
For protocol versions `2026-07-28` and later, elicitation requests are
delivered via the
[Multi Round-Trip Requests](protocol.md#multi-round-trip-requests-mrtr)
pattern.
%include ../../mcp/client_example_test.go elicitation - %include ../../mcp/client_example_test.go elicitation -
## Multi Round-Trip Requests (MRTR)
[SEP-2322](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2322)
introduces the MRTR pattern: server-to-client requests for sampling,
elicitation, and roots are no longer issued as fresh JSON-RPC requests but
are carried inside the in-flight reply of a `tools/call`, `prompts/get`, or
`resources/read`. The client must respond by retrying the original request
with the produced responses.
The SDK installs `clientMultiRoundTripMiddleware` for every client by
default. The middleware:
1. Inspects each `tools/call`/`prompts/get`/`resources/read` reply.
2. If the result's `NeedsInput()` is true, fans out the `InputRequests` map
concurrently, calling the configured handler for each (`elicit`,
`createMessage`/`createMessageWithTools`, or `listRoots`).
3. Threads the server-supplied opaque `RequestState` back unchanged.
4. Retries the original request with the responses set, repeating until the
result no longer needs input.
The middleware is enabled by default. To opt out, set
[`ClientOptions.MultiRoundTrip.Disabled = true`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#MultiRoundTripOptions);
the client will then surface `InputRequiredResult` values directly to the
caller and your code must fulfil the requests manually.
For legacy (`<= 2025-11-25`) servers, the SDK transparently sends server
requests on the legacy server-initiated channel; the MRTR machinery is a
no-op in that direction. For legacy clients talking to MRTR-style servers,
the server SDK applies the inverse compatibility shim — see the
[server-side documentation](server.md#multi-round-trip-requests-mrtr).
## Capabilities ## Capabilities
Client capabilities are advertised to servers during the initialization Client capabilities are advertised to servers during the initialization
@ -126,3 +171,11 @@ client := mcp.NewClient(impl, &mcp.ClientOptions{
}) })
``` ```
### Extensions
[SEP-2133](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2133)
adds an `extensions` map to `ClientCapabilities` and `ServerCapabilities` so
that optional capabilities outside the core protocol can be declared on the
wire. Keys are namespaced as `"{vendor-prefix}/{extension-name}"`; values
are per-extension settings objects.

View file

@ -6,15 +6,21 @@
The SDK provides an API for defining both MCP clients and servers, and The SDK provides an API for defining both MCP clients and servers, and
connecting them over various transports. When a client and server are connecting them over various transports. When a client and server are
connected, it creates a logical session, which follows the MCP spec's connected, it creates a logical session.
[lifecycle](https://modelcontextprotocol.io/specification/2025-06-18/basic/lifecycle).
In this SDK, both a The MCP specification defines two lifecycle models, and the SDK supports both
[`Client`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#Client) transparently based on the negotiated protocol version:
and
[`Server`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#Server) - The **legacy `initialize` handshake**
can handle multiple peers. Every time a new peer is connected, it creates a new ([lifecycle](https://modelcontextprotocol.io/specification/2025-06-18/basic/lifecycle))
session. used by protocol versions through `2025-11-25`.
- 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`.
In both models, the SDK exposes the same API:
- A `Client` is a logical MCP client, configured with various - A `Client` is a logical MCP client, configured with various
[`ClientOptions`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ClientOptions). [`ClientOptions`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ClientOptions).
@ -30,11 +36,16 @@ session.
[`Server.Connect`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#Server.Connect), [`Server.Connect`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#Server.Connect),
it creates a it creates a
[`ServerSession`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ServerSession). [`ServerSession`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ServerSession).
This session is not initialized until the client sends the
`notifications/initialized` message. Use `ServerOptions.InitializedHandler` In the legacy model, the server session is not considered initialized until
to listen for this event, or just use the session through various feature the client sends the `notifications/initialized` message. Use
handlers (such as a `ToolHandler`). Requests to the server are rejected until `ServerOptions.InitializedHandler` to listen for this event, or just use the
the client has initialized the session. session through various feature handlers (such as a `ToolHandler`). Requests
to the server are rejected until the client has initialized the session.
In the stateless model (`2026-07-28`+), there is no handshake. The server
processes the first request the moment it arrives, validates the per-request
`_meta` fields.
Both `ClientSession` and `ServerSession` have a `Close` method to terminate the Both `ClientSession` and `ServerSession` have a `Close` method to terminate the
session, and a `Wait` method to await session termination by the peer. Typically, session, and a `Wait` method to await session termination by the peer. Typically,
@ -42,6 +53,41 @@ it is the client's responsibility to end the session.
%include ../../mcp/mcp_example_test.go lifecycle - %include ../../mcp/mcp_example_test.go lifecycle -
### Discovery (`server/discover`)
Introduced in `2026-07-28` by
[SEP-2575](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2575),
the `server/discover` RPC lets a client discover a server's supported
protocol versions, capabilities, and identity before issuing any other
request. Servers implementing `2026-07-28` MUST implement it.
- **Server**: `Server.Connect` registers the
`server/discover` handler automatically; the response is computed from the
server's static configuration (capabilities, server info, instructions) and
the transport-filtered list of supported protocol versions.
- **Client**: `Client.Connect` calls `server/discover` first and
uses the result to negotiate a mutually supported version. If discovery
fails or the server does not support the latest version, the client falls back to the
legacy `initialize` handshake.
### Per-request `_meta` keys
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) |
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()`.
## Transports ## Transports
A A
@ -112,6 +158,39 @@ client, err := mcp.Connect(ctx, transport, &mcp.ClientOptions{...})
The `StreamableClientTransport` handles the HTTP requests and communicates with The `StreamableClientTransport` handles the HTTP requests and communicates with
the server using the streamable transport protocol. the server using the streamable transport protocol.
#### HTTP Headers
[SEP-2243](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2243)
standardises a small set of MCP-specific HTTP headers, sent and validated by
the SDK only for sessions negotiated on protocol version `2026-07-28` or
later.
| Header | Direction | Purpose |
|---|---|---|
| `Mcp-Protocol-Version` | request | Mirrors `_meta.io.modelcontextprotocol/protocolVersion` from the body |
| `Mcp-Session-Id` | request/response | Logical session identifier (removed in stateless mode) |
| `Mcp-Method` | request | Mirrors the JSON-RPC `method` field; mismatch ⇒ `-32020` |
| `Mcp-Name` | request | Mirrors the request's principal name (`tools/call.params.name`, `prompts/get.params.name`, `resources/read.params.uri`); mismatch ⇒ `-32020` |
| `Mcp-Param-{Header}` | request | Per-tool parameter passthrough; see below |
The header-name set is exhaustive: for protocol versions earlier than
`2026-07-28`, only `Mcp-Protocol-Version` and `Mcp-Session-Id` are recognised.
**Body↔header mirroring.** When `Mcp-Method` or `Mcp-Name` is present but
does not match the JSON-RPC body, the server returns
[`CodeHeaderMismatch`](#error-codes) (`-32020`). The same applies to a
mismatch between `Mcp-Protocol-Version` and the body's
`_meta.io.modelcontextprotocol/protocolVersion`.
**`Mcp-Param-*` passthrough.** A tool may annotate properties of its
`InputSchema` with `x-mcp-header: "<HeaderName>"`. When a client invokes that
tool over HTTP, the SDK serializes the matching argument(s) as
`Mcp-Param-<HeaderName>` request headers (using `=?base64?...?=` encoding for
non-ASCII values). On the server, the headers are validated against the body
and either accepted or rejected with `-32020`. Properties so annotated must
be typed `string`, `integer`, or `boolean`; tools that fail validation at
registration time are silently dropped from `tools/list`.
#### Resumability and Redelivery #### Resumability and Redelivery
By default, the streamable server does not support [resumability or By default, the streamable server does not support [resumability or
@ -125,6 +204,13 @@ value. The SDK provides a `MemoryEventStore` for testing or simple use cases;
for production use it is generally advisable to use a more sophisticated for production use it is generally advisable to use a more sophisticated
implementation. implementation.
> **Note**: [SEP-2575](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2575)
> removes SSE stream resumability (`Last-Event-ID`, SSE event IDs) for protocol
> version `2026-07-28`. The SDK preserves the `EventStore` and `Last-Event-ID`
> code paths for backward compatibility with `2025-11-25` and earlier; on
> `2026-07-28` sessions, a broken response stream loses the in-flight request
> and the client must re-issue it as a new request with a new ID.
#### Stateless Mode #### Stateless Mode
The streamable server supports a _stateless mode_ by setting The streamable server supports a _stateless mode_ by setting
@ -143,6 +229,10 @@ to see the logical session
> modelcontextprotocol/modelcontextprotocol#1372, or > modelcontextprotocol/modelcontextprotocol#1372, or
> modelcontextprotocol/modelcontextprotocol#1442 for potential refinements. > modelcontextprotocol/modelcontextprotocol#1442 for potential refinements.
> **Required for `2026-07-28`**: the streamable HTTP transport accepts
> requests at protocol version `2026-07-28` **only** when `Stateless = true`.
> Requests at that version against a non-stateless handler are rejected.
_See [examples/server/distributed](https://github.com/modelcontextprotocol/go-sdk/blob/main/examples/server/distributed/main.go) for _See [examples/server/distributed](https://github.com/modelcontextprotocol/go-sdk/blob/main/examples/server/distributed/main.go) for
an example using stateless mode to implement a server distributed across an example using stateless mode to implement a server distributed across
multiple processes._ multiple processes._
@ -463,6 +553,13 @@ session if the ping fails, set
or or
[`ServerOptions.KeepAlive`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ServerOptions.KeepAlive). [`ServerOptions.KeepAlive`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#ServerOptions.KeepAlive).
> **Note**: `ping` is removed from the protocol as of `2026-07-28` by
> [SEP-2575](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2575).
> The SDK preserves the API for backward compatibility with legacy clients;
> when both peers negotiate `2026-07-28`, the server returns
> `MethodNotFound` (`-32601`) for `ping` and `KeepAlive` should not be
> enabled.
### Progress ### Progress
[Progress](https://modelcontextprotocol.io/specification/2025-06-18/basic/utilities/progress) [Progress](https://modelcontextprotocol.io/specification/2025-06-18/basic/utilities/progress)
@ -480,3 +577,22 @@ Issue #460 discusses some potential ergonomic improvements to this API.
%include ../../mcp/mcp_example_test.go progress - %include ../../mcp/mcp_example_test.go progress -
### Error codes
The SDK uses the standard JSON-RPC base codes (parse error `-32700`,
invalid request `-32600`, method not found `-32601`, invalid params
`-32602`, internal error `-32603`) plus the following MCP-specific codes:
| Constant | Code | Meaning |
|---|---|---|
| [`CodeHeaderMismatch`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#CodeHeaderMismatch) | `-32020` | An MCP HTTP header (`Mcp-Method`, `Mcp-Name`, `Mcp-Protocol-Version`, or `Mcp-Param-*`) does not match the JSON-RPC body |
| [`CodeMissingRequiredClientCapabilities`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#CodeMissingRequiredClientCapabilities) | `-32021` | Server requires client capabilities the client did not declare |
| [`CodeUnsupportedProtocolVersion`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#CodeUnsupportedProtocolVersion) | `-32022` | Requested protocol version not supported. Data: `UnsupportedProtocolVersionData{Supported []string, Requested string}` |
| [`CodeResourceNotFound`](https://pkg.go.dev/github.com/modelcontextprotocol/go-sdk/mcp#CodeResourceNotFound) | `-32602` | Resource URI not found (variable; was `-32002` before SEP-2164) |
The error code allocation policy defined in `2026-07-28`
([SEP-2575](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2575))
partitions the JSON-RPC server-error range:
- `-32000` to `-32019`: implementation-defined; existing SDK usage is grandfathered.
- `-32020` to `-32099`: reserved for the MCP specification.

View file

@ -214,6 +214,80 @@ func handleRequest(w http.ResponseWriter, r *http.Request) {
} }
``` ```
## Multi Round-Trip Requests (MRTR)
[SEP-2322](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2322)
defines a new pattern for server-to-client requests (sampling, elicitation,
roots). Instead of issuing a fresh JSON-RPC request mid-flight, the server
returns an `InputRequiredResult` from its in-flight handler — the
`InputRequests` field of `CallToolResult`, `GetPromptResult`, or
`ReadResourceResult` carries the requests for additional information. The
client responds by retrying the original call with `InputResponses` set.
The SDK supports this pattern from both sides without requiring callers to
choose:
- **Returning input requests from a handler.** Set `InputRequests` on the
result you return.
Leave `Content` / `StructuredContent` empty — returning
both at once is a server bug and the SDK returns `-32603 InternalError`.
- **Calling the legacy APIs.** `ServerSession.Elicit`,
`ServerSession.CreateMessage(WithTools)`, and `ServerSession.ListRoots`
remain available and work for both new and legacy clients.
### Talking to legacy clients
The server installs `serverMultiRoundTripMiddleware` automatically. For
clients on a protocol version earlier than `2026-07-28`, the middleware
intercepts any `InputRequiredResult` your handler returns, fulfils each
input request itself by calling the legacy server-initiated APIs
(`Elicit`, `CreateMessage`, `ListRoots`), and re-invokes your handler
exactly once with the responses already populated. This means a handler
written in the MRTR style works against both old and new clients without
code changes.
### Example
The following example shows a "greet" tool whose handler asks the user
for their name via elicitation before producing the final greeting. The
handler runs twice — once to issue the elicitation, once to consume the
response — but the client call site sees a single `CallTool` returning the
final result, because the SDK's MRTR middleware handles the round trip on
either side of the wire (depending on the negotiated protocol version).
%include ../../mcp/server_example_test.go mrtr -
## Cacheable list results
[SEP-2549](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2549)
adds `ttlMs` and `cacheScope` fields to the results of `tools/list`,
`prompts/list`, `resources/list`, `resources/templates/list`, and
`resources/read`. Both fields complement existing list
results: clients use `ttlMs` as a freshness hint to reduce polling,
and `cacheScope` (`"public"` or `"private"`) controls whether shared
intermediaries may cache the response.
**Server-side defaults.** After paginating, the SDK sets `CacheScope = "public"`
and leaves `TTLMs = 0` (which the client cache treats as "immediately
stale"). A handler that wants its responses cached must set `TTLMs`
explicitly on the returned result.
```go
mcp.AddTool(server, &mcp.Tool{Name: "expensive"}, func(...) (*mcp.CallToolResult, any, error) {
// ...
})
// Override the default for tools/list:
server.AddSendingMiddleware(func(next mcp.MethodHandler) mcp.MethodHandler {
return func(ctx context.Context, method string, req mcp.Request) (mcp.Result, error) {
res, err := next(ctx, method, req)
if lr, ok := res.(*mcp.ListToolsResult); ok {
lr.TTLMs = 30_000 // 30s cache freshness hint
}
return res, err
}
})
```
## Utilities ## Utilities
### Completion ### Completion
@ -318,6 +392,14 @@ server := mcp.NewServer(impl, &mcp.ServerOptions{
**Deprecated**: The `HasPrompts`, `HasResources`, and `HasTools` fields on **Deprecated**: The `HasPrompts`, `HasResources`, and `HasTools` fields on
`ServerOptions` are deprecated. Use `Capabilities` instead. `ServerOptions` are deprecated. Use `Capabilities` instead.
### Extensions
[SEP-2133](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2133)
adds an `extensions` map to `ServerCapabilities` so that optional
capabilities outside the core protocol can be declared on the wire. Keys
are namespaced as `"{vendor-prefix}/{extension-name}"`; values are
per-extension settings objects.
### Pagination ### Pagination
Server-side feature lists may be Server-side feature lists may be

View file

@ -33,11 +33,12 @@ contains feature documentation, mapping the MCP spec to the packages above.
The following table shows which versions of the Go SDK support which versions of the MCP specification: The following table shows which versions of the Go SDK support which versions of the MCP specification:
| SDK Version | Latest MCP Spec | All Supported MCP Specs | | SDK Version | Latest MCP Spec | All Supported MCP Specs |
|-----------------|-------------------|----------------------------------------------------| |-----------------|-------------------|------------------------------------------------------------------|
| v1.4.0+ | 2025-11-25\* | 2025-11-25\*, 2025-06-18, 2025-03-26, 2024-11-05 | | v1.7.0+ | 2026-07-28 | 2026-07-28, 2025-11-25\*, 2025-06-18, 2025-03-26, 2024-11-05 |
| v1.2.0 - v1.3.1 | 2025-11-25\*\* | 2025-11-25\*\*, 2025-06-18, 2025-03-26, 2024-11-05 | | v1.4.0 - v1.6.1 | 2025-11-25\* | 2025-11-25\*, 2025-06-18, 2025-03-26, 2024-11-05 |
| v1.0.0 - v1.1.0 | 2025-06-18 | 2025-06-18, 2025-03-26, 2024-11-05 | | v1.2.0 - v1.3.1 | 2025-11-25\*\* | 2025-11-25\*\*, 2025-06-18, 2025-03-26, 2024-11-05 |
| v1.0.0 - v1.1.0 | 2025-06-18 | 2025-06-18, 2025-03-26, 2024-11-05 |
\* Client side OAuth has experimental support. \* Client side OAuth has experimental support.

View file

@ -13,6 +13,7 @@ import (
"log/slog" "log/slog"
"sync/atomic" "sync/atomic"
"github.com/google/jsonschema-go/jsonschema"
"github.com/modelcontextprotocol/go-sdk/mcp" "github.com/modelcontextprotocol/go-sdk/mcp"
) )
@ -220,3 +221,89 @@ func Example_resources() {
} }
// !-resources // !-resources
// !+mrtr
// Example_mrtr demonstrates the [Multi Round-Trip Requests] pattern
// (SEP-2322). A tool handler signals "I need more information from the user"
// by returning a [mcp.CallToolResult] whose `InputRequests` field carries the
// requests for the additional information. Each request can be an
// [mcp.ElicitParams] (ask the user a question),
// [mcp.CreateMessageParams] (sample from the client's LLM), or
// [mcp.ListRootsParams] (list the client's roots).
//
// On protocol version `2026-07-28` and later, the client's
// `clientMultiRoundTripMiddleware` fulfils each input request from the
// configured handler and retries the original call transparently. On earlier
// protocol versions, the server's `serverMultiRoundTripMiddleware` performs
// the equivalent dance from the server side by calling the legacy
// server-to-client API (`ServerSession.Elicit`, `CreateMessage`, or
// `ListRoots`) and re-invoking the handler with the response. Either way,
// the user-facing client call site sees only the final result.
//
// [Multi Round-Trip Requests]: https://modelcontextprotocol.io/specification/draft/basic/patterns#multi-round-trip-requests
func Example_mrtr() {
ctx := context.Background()
// Server: a "greet" tool that asks the user for their name before
// returning a greeting. The handler runs twice per logical call:
// once to issue the elicitation, once to consume the response.
s := mcp.NewServer(&mcp.Implementation{Name: "server", Version: "v0.0.1"}, nil)
mcp.AddTool(s, &mcp.Tool{Name: "greet"}, func(_ context.Context, req *mcp.CallToolRequest, _ struct{}) (*mcp.CallToolResult, any, error) {
if len(req.Params.InputResponses) == 0 {
// First call: ask the user for their name. The map key
// ("user_name") is a label the handler chooses; the client must
// echo it back in InputResponses. The wire-level method name
// ("elicitation/create") is derived from the value's Go type.
return &mcp.CallToolResult{
InputRequests: mcp.InputRequestMap{
"user_name": &mcp.ElicitParams{
Message: "What's your name?",
RequestedSchema: &jsonschema.Schema{
Type: "object",
Properties: map[string]*jsonschema.Schema{
"name": {Type: "string"},
},
},
},
},
// RequestState is an opaque token the client echoes back on
// the retry, letting the handler resume its work without
// per-session storage.
RequestState: "step=1",
}, nil, nil
}
// Retry: read the elicitation response and produce the final greeting.
name := req.Params.InputResponses["user_name"].(*mcp.ElicitResult).Content["name"].(string)
return &mcp.CallToolResult{
Content: []mcp.Content{&mcp.TextContent{Text: "Hello " + name}},
}, nil, nil
})
// Client: declares an elicitation handler. The SDK's MRTR middleware
// uses it to fulfil any input request the tool handler returns.
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{"name": "Ada"}}, nil
},
})
ct, st := mcp.NewInMemoryTransports()
if _, err := s.Connect(ctx, st, nil); err != nil {
log.Fatal(err)
}
cs, err := c.Connect(ctx, ct, nil)
if err != nil {
log.Fatal(err)
}
defer cs.Close()
// Single call site. The MRTR round trip is invisible to the caller.
res, err := cs.CallTool(ctx, &mcp.CallToolParams{Name: "greet"})
if err != nil {
log.Fatal(err)
}
fmt.Println(res.Content[0].(*mcp.TextContent).Text)
}
// !-mrtr