Skip to content

Commit 206050f

Browse files
committed
docs: update for 2026-07-28 version
1 parent aad4d4e commit 206050f

5 files changed

Lines changed: 236 additions & 1042 deletions

File tree

README.md

Lines changed: 199 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,13 @@ This repository contains the following crates:
1717
- [rmcp](crates/rmcp): The core crate providing the RMCP protocol implementation - see [rmcp](crates/rmcp/README.md)
1818
- [rmcp-macros](crates/rmcp-macros): A procedural macro crate for generating RMCP tool implementations - see [rmcp-macros](crates/rmcp-macros/README.md)
1919

20-
For the full MCP specification, see [modelcontextprotocol.io](https://modelcontextprotocol.io/specification/2025-11-25).
20+
This SDK tracks the MCP **`2026-07-28`** draft (the current development spec)
21+
while remaining fully compatible with the stable **`2025-11-25`** release and
22+
earlier versions. New `2026-07-28` features — server discovery & negotiation,
23+
transport-neutral subscriptions, long-running tasks, response caching,
24+
multi-round-trip requests, and standard HTTP routing headers — are documented
25+
below alongside the stable feature set. For the full MCP specification, see
26+
[modelcontextprotocol.io](https://modelcontextprotocol.io/specification/draft).
2127

2228
## Table of Contents
2329

@@ -31,8 +37,11 @@ For the full MCP specification, see [modelcontextprotocol.io](https://modelconte
3137
- [Completions](#completions)
3238
- [Notifications](#notifications)
3339
- [Subscriptions](#subscriptions)
40+
- [Multi-Round-Trip Requests](#multi-round-trip-requests)
3441
- [Tasks](#tasks-long-running-tool-invocations)
3542
- [Caching](#caching)
43+
- [Standard HTTP Headers](#standard-http-headers)
44+
- [Stateless Streamable HTTP](#stateless-streamable-http)
3645
- [Examples](#examples)
3746
- [OAuth Support](#oauth-support)
3847
- [Related Resources](#related-resources)
@@ -44,7 +53,7 @@ For the full MCP specification, see [modelcontextprotocol.io](https://modelconte
4453
### Import the crate
4554

4655
```toml
47-
rmcp = { version = "0.16.0", features = ["server"] }
56+
rmcp = { version = "2.2.0", features = ["server"] }
4857
## or dev channel
4958
rmcp = { git = "https://github.com/modelcontextprotocol/rust-sdk", branch = "main" }
5059
```
@@ -174,7 +183,7 @@ let quit_reason = server.cancel().await?;
174183

175184
Tools let servers expose callable functions to clients. Each tool has a name, description, and a JSON Schema for its parameters. Clients discover tools via `list_tools` and invoke them via `call_tool`.
176185

177-
**MCP Spec:** [Tools](https://modelcontextprotocol.io/specification/2025-11-25/server/tools)
186+
**MCP Spec:** [Tools](https://modelcontextprotocol.io/specification/draft/server/tools)
178187

179188
### Server-side
180189

@@ -210,6 +219,11 @@ async fn main() -> anyhow::Result<()> {
210219

211220
The generated tool `inputSchema` and `outputSchema` are derived from the fields of `T`. The type name and documentation on `T` are ignored; only field names, field types, and field documentation are used.
212221

222+
> **`2026-07-28` (SEP-2106):** `outputSchema` may now be any JSON Schema type
223+
> (not just `object`), and a tool result's `structuredContent` may be any JSON
224+
> value (string, array, number, …) rather than only an object. Existing
225+
> object-typed tools are unaffected.
226+
213227
When you need custom server metadata or multiple capabilities (tools + prompts), use explicit `#[tool_handler]`:
214228

215229
```rust,ignore
@@ -258,7 +272,7 @@ let result = client.call_tool(CallToolRequestParams::new("add")).await?;
258272

259273
Resources let servers expose data (files, database records, API responses) that clients can read. Each resource is identified by a URI and returns content as text or binary (base64-encoded) data. Resource templates allow servers to declare URI patterns with dynamic parameters.
260274

261-
**MCP Spec:** [Resources](https://modelcontextprotocol.io/specification/2025-11-25/server/resources)
275+
**MCP Spec:** [Resources](https://modelcontextprotocol.io/specification/draft/server/resources)
262276

263277
### Server-side
264278

@@ -393,7 +407,7 @@ impl ClientHandler for MyClient {
393407

394408
Prompts are reusable message templates that servers expose to clients. They accept typed arguments and return conversation messages. The `#[prompt]` macro handles argument validation and routing automatically.
395409

396-
**MCP Spec:** [Prompts](https://modelcontextprotocol.io/specification/2025-11-25/server/prompts)
410+
**MCP Spec:** [Prompts](https://modelcontextprotocol.io/specification/draft/server/prompts)
397411

398412
### Server-side
399413

@@ -507,7 +521,7 @@ context.peer.notify_prompt_list_changed().await?;
507521
508522
Sampling flips the usual direction: the server asks the client to run an LLM completion. The server sends a `create_message` request, the client processes it through its LLM, and returns the result.
509523

510-
**MCP Spec:** [Sampling](https://modelcontextprotocol.io/specification/2025-11-25/client/sampling)
524+
**MCP Spec:** [Sampling](https://modelcontextprotocol.io/specification/draft/client/sampling)
511525

512526
### Server-side (requesting sampling)
513527

@@ -579,7 +593,7 @@ impl ClientHandler for MyClient {
579593
580594
Roots tell servers which directories or projects the client is working in. A root is a URI (typically `file://`) pointing to a workspace or repository. Servers can query roots to know where to look for files and how to scope their work.
581595

582-
**MCP Spec:** [Roots](https://modelcontextprotocol.io/specification/2025-11-25/client/roots)
596+
**MCP Spec:** [Roots](https://modelcontextprotocol.io/specification/draft/client/roots)
583597

584598
### Server-side
585599

@@ -644,7 +658,7 @@ client.notify_roots_list_changed().await?;
644658
645659
Servers can send structured log messages to clients. The client sets a minimum severity level, and the server sends messages through the peer notification interface.
646660

647-
**MCP Spec:** [Logging](https://modelcontextprotocol.io/specification/2025-11-25/server/utilities/logging)
661+
**MCP Spec:** [Logging](https://modelcontextprotocol.io/specification/draft/server/utilities/logging)
648662

649663
### Server-side
650664

@@ -717,7 +731,7 @@ client.set_level(SetLevelRequestParams::new(LoggingLevel::Warning)).await?;
717731

718732
Completions give auto-completion suggestions for prompt or resource template arguments. As a user fills in arguments, the client can ask the server for suggestions based on what's already been entered.
719733

720-
**MCP Spec:** [Completions](https://modelcontextprotocol.io/specification/2025-11-25/server/utilities/completion)
734+
**MCP Spec:** [Completions](https://modelcontextprotocol.io/specification/draft/server/utilities/completion)
721735

722736
### Server-side
723737

@@ -799,7 +813,7 @@ let result = client.complete(CompleteRequestParams::new(
799813

800814
Notifications are fire-and-forget messages -- no response is expected. They cover progress updates, cancellation, and lifecycle events. Both sides can send and receive them.
801815

802-
**MCP Spec:** [Notifications](https://modelcontextprotocol.io/specification/2025-11-25/basic/notifications)
816+
**MCP Spec:** [Notifications](https://modelcontextprotocol.io/specification/draft/basic#notifications)
803817

804818
### Progress notifications
805819

@@ -970,6 +984,81 @@ and [client](examples/clients/src/subscriptions_streamhttp.rs) examples.
970984

971985
---
972986

987+
## Multi-Round-Trip Requests
988+
989+
Protocol `2026-07-28` adds Multi-Round-Trip Requests (MRTR, SEP-2322): a server
990+
can answer a `tools/call`, `prompts/get`, or `resources/read` with an
991+
`InputRequiredResult` instead of a final result, asking the client to fulfill
992+
one or more embedded server requests (elicitation, sampling, or roots) and then
993+
retry. The exchange is stateless — the server carries its progress in an opaque
994+
`requestState` that the client echoes back verbatim.
995+
996+
**MCP Spec:** [Multiple Round-Trip Requests](https://modelcontextprotocol.io/specification/draft/server/tools#multiple-round-trip-requests)
997+
998+
### Server-side
999+
1000+
Return an `InputRequiredResult` via the outcome enum for the method
1001+
(`CallToolResponse`, `GetPromptResponse`, or `ReadResourceResponse`). The SDK
1002+
only forwards it to peers that negotiated `2026-07-28` or newer — older peers
1003+
get a protocol error instead.
1004+
1005+
```rust, ignore
1006+
async fn call_tool(&self, request: CallToolRequestParams, _ctx: RequestContext<RoleServer>)
1007+
-> Result<CallToolResponse, ErrorData>
1008+
{
1009+
match request.request_state {
1010+
// First round: ask the client for input, seal progress into requestState.
1011+
None => {
1012+
let mut input_requests = InputRequests::new();
1013+
input_requests.insert("city".into(), InputRequest::Elicitation(elicit_city()));
1014+
let sealed = self.codec.seal_json(&json!({ "awaiting": "city" }))?;
1015+
Ok(InputRequiredResult::new(Some(input_requests), Some(sealed)).into())
1016+
}
1017+
// Retry round: verify the echoed state, read the responses, finish.
1018+
Some(sealed) => {
1019+
let _state = self.codec.open_json(&sealed)
1020+
.map_err(|_| ErrorData::invalid_params("tampered request state", None))?;
1021+
let city = request.input_responses.as_ref()
1022+
.and_then(|r| r.get("city"));
1023+
Ok(CallToolResult::success(vec![ContentBlock::text("It is sunny.")]).into())
1024+
}
1025+
}
1026+
}
1027+
```
1028+
1029+
> **`requestState` is untrusted.** The client echoes it back verbatim, so a
1030+
> stateless server that stores meaningful data in it MUST verify integrity
1031+
> first. Enable the `request-state` feature and use `RequestStateCodec` to seal
1032+
> and open it (HMAC-tagged), or keep state server-side and use `requestState`
1033+
> only as an opaque handle.
1034+
1035+
### Client-side
1036+
1037+
The high-level `call_tool`, `get_prompt`, and `read_resource` helpers drive MRTR
1038+
automatically: they fulfill each embedded request through the local
1039+
`ClientHandler` and retry, up to `DEFAULT_MRTR_MAX_ROUNDS` (10).
1040+
1041+
```rust, ignore
1042+
// Auto mode: the SDK fulfills embedded requests and retries for you.
1043+
let result = client.call_tool(CallToolRequestParams::new("weather")).await?;
1044+
1045+
// Choose a custom round cap.
1046+
let result = client
1047+
.call_tool_with_mrtr_max_rounds(CallToolRequestParams::new("weather"), 3)
1048+
.await?;
1049+
1050+
// Manual mode: get the intermediate InputRequiredResult and drive rounds yourself.
1051+
match client.call_tool_once(CallToolRequestParams::new("weather")).await? {
1052+
CallToolResponse::InputRequired(input_required) => { /* fulfill + retry */ }
1053+
CallToolResponse::Complete(result) => { /* done */ }
1054+
_ => {}
1055+
}
1056+
```
1057+
1058+
**Example:** [`examples/servers/src/mrtr.rs`](examples/servers/src/mrtr.rs) (end-to-end server + client)
1059+
1060+
---
1061+
9731062
## Tasks (long-running tool invocations)
9741063

9751064
`rmcp` implements the [MCP Tasks extension](https://modelcontextprotocol.io/extensions/tasks/overview)
@@ -1050,6 +1139,104 @@ peer.clear_response_cache().await;
10501139
> last cached response (even if expired) as `Ok(..)` instead of an error. Set
10511140
> `with_serve_stale_on_error(false)` if callers must observe fetch failures.
10521141
1142+
## Standard HTTP Headers
1143+
1144+
Protocol `2026-07-28` standardizes a set of Streamable HTTP request headers
1145+
(SEP-2243) so proxies and gateways can route MCP traffic without parsing the
1146+
JSON body: `Mcp-Method`, `Mcp-Name`, and `Mcp-Param-*`. `rmcp` emits and
1147+
validates these automatically once a connection negotiates `2026-07-28` or
1148+
newer — no call-site changes are required, and older negotiated versions are
1149+
untouched.
1150+
1151+
**MCP Spec:** [Header standardization](https://modelcontextprotocol.io/specification/draft/basic/transports#header)
1152+
1153+
- `Mcp-Method` — the JSON-RPC method (e.g. `tools/call`).
1154+
- `Mcp-Name` — the target name, sourced from `params.name` (`tools/call`,
1155+
`prompts/get`), `params.uri` (`resources/*`), or `params.taskId` (`tasks/*`).
1156+
- `Mcp-Param-*` — selected `tools/call` arguments, promoted from the tool's
1157+
input schema.
1158+
1159+
To promote a tool argument into a routing header, annotate the top-level schema
1160+
property with `x-mcp-header`:
1161+
1162+
```rust, ignore
1163+
// A `region` argument surfaces as the `Mcp-Param-Region` request header.
1164+
let schema = serde_json::json!({
1165+
"type": "object",
1166+
"properties": {
1167+
"region": { "type": "string", "x-mcp-header": "Region" }
1168+
}
1169+
});
1170+
```
1171+
1172+
Annotations must be non-empty RFC 9110 tokens, case-insensitively unique, and
1173+
applied only to top-level primitive (`string`/`integer`/`boolean`) properties.
1174+
Values that cannot travel as a bare header (leading/trailing whitespace,
1175+
control/non-ASCII characters) are transparently Base64-wrapped as
1176+
`=?base64?<b64>?=`.
1177+
1178+
---
1179+
1180+
## Stateless Streamable HTTP
1181+
1182+
Per SEP-2567, `rmcp` serves the `2026-07-28` draft statelessly **automatically**:
1183+
no `Mcp-Session-Id`, no standalone GET/DELETE stream, and no `Last-Event-ID`
1184+
resumption. The `legacy_session_mode` flag below only controls behavior for
1185+
*legacy* protocol versions (`< 2026-07-28`).
1186+
1187+
**MCP Spec:** [Transports](https://modelcontextprotocol.io/specification/draft/basic/transports)
1188+
1189+
### Server-side
1190+
1191+
A default server already serves `2026-07-28` clients statelessly. To also serve
1192+
*legacy* clients without sessions, disable `legacy_session_mode` (formerly
1193+
`stateful_mode`; builder `with_stateful_mode`). Optionally set
1194+
`with_json_response(true)` so simple request/response tools reply with a single
1195+
`application/json` body instead of an SSE stream (the server still falls back to
1196+
`text/event-stream` if a handler emits a notification or server request first):
1197+
1198+
```rust, ignore
1199+
use rmcp::transport::streamable_http_server::{
1200+
StreamableHttpService, StreamableHttpServerConfig,
1201+
session::local::LocalSessionManager,
1202+
};
1203+
1204+
let config = StreamableHttpServerConfig::default()
1205+
.with_legacy_session_mode(false) // stateless for legacy versions too
1206+
.with_json_response(true); // plain JSON replies for simple tools
1207+
1208+
let service = StreamableHttpService::new(
1209+
|| Ok(Counter::new()), // a fresh handler per request
1210+
LocalSessionManager::default().into(),
1211+
config,
1212+
);
1213+
1214+
// `StreamableHttpService` is a Tower service — mount it on any router.
1215+
let router = axum::Router::new().nest_service("/mcp", service);
1216+
```
1217+
1218+
> Because there is no per-session state, the `service_factory` runs per request.
1219+
> Keep shared state (DB pools, caches) in a `Clone` handle captured by the
1220+
> closure; don't rely on in-memory state surviving between requests.
1221+
1222+
### Client-side
1223+
1224+
The Streamable HTTP client transport allows stateless operation by default
1225+
(`allow_stateless: true`), so no configuration is needed to talk to a stateless
1226+
server — it simply omits the session header when the server doesn't issue one:
1227+
1228+
```rust, ignore
1229+
use rmcp::transport::StreamableHttpClientTransport;
1230+
1231+
// Defaults are stateless-friendly.
1232+
let transport = StreamableHttpClientTransport::from_uri("http://localhost:8000/mcp");
1233+
let client = ClientInfo::default().serve(transport).await?;
1234+
```
1235+
1236+
**Example:** [`examples/servers/src/counter_streamhttp.rs`](examples/servers/src/counter_streamhttp.rs) (server), [`examples/clients/src/streamable_http.rs`](examples/clients/src/streamable_http.rs) (client)
1237+
1238+
---
1239+
10531240
## Examples
10541241

10551242
See [examples](examples/README.md).
@@ -1060,8 +1247,8 @@ See [Oauth_support](docs/OAUTH_SUPPORT.md) for details.
10601247

10611248
## Related Resources
10621249

1063-
- [MCP Specification](https://modelcontextprotocol.io/specification/2025-11-25)
1064-
- [Schema](https://github.com/modelcontextprotocol/specification/blob/main/schema/2025-11-25/schema.ts)
1250+
- [MCP Specification](https://modelcontextprotocol.io/specification/draft)
1251+
- [Schema](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/schema/draft/schema.ts)
10651252

10661253
## Related Projects
10671254

0 commit comments

Comments
 (0)