Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 21 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,20 @@

An official Rust Model Context Protocol SDK implementation with tokio async runtime.

> **Migrating to 1.x?** See the [migration guide](https://github.com/modelcontextprotocol/rust-sdk/discussions/716) for breaking changes and upgrade instructions.
> **Migrating to 3.x?** See the [migration guide](https://github.com/modelcontextprotocol/rust-sdk/discussions/969) for breaking changes and upgrade instructions.

This repository contains the following crates:

- [rmcp](crates/rmcp): The core crate providing the RMCP protocol implementation - see [rmcp](crates/rmcp/README.md)
- [rmcp-macros](crates/rmcp-macros): A procedural macro crate for generating RMCP tool implementations - see [rmcp-macros](crates/rmcp-macros/README.md)

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

## Table of Contents

Expand Down Expand Up @@ -185,7 +185,7 @@ let quit_reason = server.cancel().await?;

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`.

**MCP Spec:** [Tools](https://modelcontextprotocol.io/specification/draft/server/tools)
**MCP Spec:** [Tools](https://modelcontextprotocol.io/specification/2026-07-28/server/tools)

### Server-side

Expand Down Expand Up @@ -274,7 +274,7 @@ let result = client.call_tool(CallToolRequestParams::new("add")).await?;

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.

**MCP Spec:** [Resources](https://modelcontextprotocol.io/specification/draft/server/resources)
**MCP Spec:** [Resources](https://modelcontextprotocol.io/specification/2026-07-28/server/resources)

### Server-side

Expand Down Expand Up @@ -409,7 +409,7 @@ impl ClientHandler for MyClient {

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.

**MCP Spec:** [Prompts](https://modelcontextprotocol.io/specification/draft/server/prompts)
**MCP Spec:** [Prompts](https://modelcontextprotocol.io/specification/2026-07-28/server/prompts)

### Server-side

Expand Down Expand Up @@ -523,7 +523,7 @@ context.peer.notify_prompt_list_changed().await?;

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.

**MCP Spec:** [Sampling](https://modelcontextprotocol.io/specification/draft/client/sampling)
**MCP Spec:** [Sampling](https://modelcontextprotocol.io/specification/2026-07-28/client/sampling)

### Server-side (requesting sampling)

Expand Down Expand Up @@ -595,7 +595,7 @@ impl ClientHandler for MyClient {

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.

**MCP Spec:** [Roots](https://modelcontextprotocol.io/specification/draft/client/roots)
**MCP Spec:** [Roots](https://modelcontextprotocol.io/specification/2026-07-28/client/roots)

### Server-side

Expand Down Expand Up @@ -660,7 +660,7 @@ client.notify_roots_list_changed().await?;

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.

**MCP Spec:** [Logging](https://modelcontextprotocol.io/specification/draft/server/utilities/logging)
**MCP Spec:** [Logging](https://modelcontextprotocol.io/specification/2026-07-28/server/utilities/logging)

### Server-side

Expand Down Expand Up @@ -733,7 +733,7 @@ client.set_level(SetLevelRequestParams::new(LoggingLevel::Warning)).await?;

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.

**MCP Spec:** [Completions](https://modelcontextprotocol.io/specification/draft/server/utilities/completion)
**MCP Spec:** [Completions](https://modelcontextprotocol.io/specification/2026-07-28/server/utilities/completion)

### Server-side

Expand Down Expand Up @@ -815,7 +815,7 @@ let result = client.complete(CompleteRequestParams::new(

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.

**MCP Spec:** [Notifications](https://modelcontextprotocol.io/specification/draft/basic#notifications)
**MCP Spec:** [Notifications](https://modelcontextprotocol.io/specification/2026-07-28/basic#notifications)

### Progress notifications

Expand Down Expand Up @@ -903,7 +903,7 @@ Protocol `2026-07-28` replaces `resources/subscribe`, `resources/unsubscribe`, a
the standalone HTTP GET stream with the transport-neutral, long-lived
`subscriptions/listen` request. Each requested notification category is opt-in.

**MCP Spec:** [Subscriptions](https://modelcontextprotocol.io/specification/draft/basic/patterns/subscriptions)
**MCP Spec:** [Subscriptions](https://modelcontextprotocol.io/specification/2026-07-28/basic/patterns/subscriptions)

### Server-side

Expand Down Expand Up @@ -995,7 +995,7 @@ one or more embedded server requests (elicitation, sampling, or roots) and then
retry. The exchange is stateless — the server carries its progress in an opaque
`requestState` that the client echoes back verbatim.

**MCP Spec:** [Multiple Round-Trip Requests](https://modelcontextprotocol.io/specification/draft/server/tools#multiple-round-trip-requests)
**MCP Spec:** [Multiple Round-Trip Requests](https://modelcontextprotocol.io/specification/2026-07-28/server/tools#multiple-round-trip-requests)

### Server-side

Expand Down Expand Up @@ -1098,7 +1098,7 @@ See [`servers_task_stdio`](examples/servers/src/task_stdio.rs) and the matching
## Caching

`rmcp` clients transparently cache responses that carry the
[SEP-2549](https://modelcontextprotocol.io/specification/draft/server/utilities/caching)
[SEP-2549](https://modelcontextprotocol.io/specification/2026-07-28/server/utilities/caching)
caching hints (`ttlMs` / `cacheScope`) for `server/discover`, `tools/list`,
`prompts/list`, `resources/list`, `resources/templates/list`, and `resources/read`.

Expand Down Expand Up @@ -1150,7 +1150,7 @@ validates these automatically once a connection negotiates `2026-07-28` or
newer — no call-site changes are required, and older negotiated versions are
untouched.

**MCP Spec:** [Header standardization](https://modelcontextprotocol.io/specification/draft/basic/transports#header)
**MCP Spec:** [Header standardization](https://modelcontextprotocol.io/specification/2026-07-28/basic/transports#header)

- `Mcp-Method` — the JSON-RPC method (e.g. `tools/call`).
- `Mcp-Name` — the target name, sourced from `params.name` (`tools/call`,
Expand Down Expand Up @@ -1186,7 +1186,7 @@ no `Mcp-Session-Id`, no standalone GET/DELETE stream, and no `Last-Event-ID`
resumption. The `legacy_session_mode` flag below only controls behavior for
*legacy* protocol versions (`< 2026-07-28`).

**MCP Spec:** [Transports](https://modelcontextprotocol.io/specification/draft/basic/transports)
**MCP Spec:** [Transports](https://modelcontextprotocol.io/specification/2026-07-28/basic/transports)

### Server-side

Expand Down Expand Up @@ -1249,8 +1249,8 @@ See [Oauth_support](docs/OAUTH_SUPPORT.md) for details.

## Related Resources

- [MCP Specification](https://modelcontextprotocol.io/specification/draft)
- [Schema](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/schema/draft/schema.ts)
- [MCP Specification](https://modelcontextprotocol.io/specification/2026-07-28)
- [Schema](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/schema/2026-07-28/schema.ts)

## Related Projects

Expand Down
2 changes: 1 addition & 1 deletion crates/rmcp/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

</div>

The official Rust SDK for the [Model Context Protocol](https://modelcontextprotocol.io/specification/draft). Build MCP servers that expose tools, resources, and prompts to AI assistants — or build clients that connect to them.
The official Rust SDK for the [Model Context Protocol](https://modelcontextprotocol.io/specification/2026-07-28). Build MCP servers that expose tools, resources, and prompts to AI assistants — or build clients that connect to them.

For **getting started**, **usage guides**, and **full MCP feature documentation** (resources, prompts, sampling, roots, logging, completions, subscriptions, etc.), see the [main README](../../README.md).

Expand Down
4 changes: 2 additions & 2 deletions crates/rmcp/src/handler/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ impl<H: ServerHandler> Service<RoleServer> for H {
let subscription_id = context.id.clone();
let subscription =
SubscriptionContext::establish(context, requested, accepted).await?;
// The integrated draft schema defines a final result for graceful
// The 2026-07-28 schema defines a final result for graceful
// server teardown; explicit stdio cancellation remains a notification.
self.listen(subscription).await.map(|()| {
ServerResult::SubscriptionsListenResult(
Expand Down Expand Up @@ -405,7 +405,7 @@ macro_rules! server_handler_methods {
///
/// The SDK sends the acknowledgment before invoking this method. Returning
/// `Ok(())` sends the final [`SubscriptionsListenResult`] defined by the
/// integrated draft schema, marking graceful server teardown. Explicit
/// 2026-07-28 schema, marking graceful server teardown. Explicit
/// stdio cancellation uses `notifications/cancelled` instead.
fn listen(
&self,
Expand Down
16 changes: 8 additions & 8 deletions crates/rmcp/src/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -503,9 +503,9 @@ pub struct JsonRpcResponse<R = JsonObject> {
#[expect(clippy::exhaustive_structs, reason = "intentionally exhaustive")]
pub struct JsonRpcError {
pub jsonrpc: JsonRpcVersion2_0,
// MCP 2025-11-25 §Error Responses: `id` is optional and omitted when the
// MCP 2026-07-28 §Error Responses: `id` is optional and omitted when the
// server cannot read the request id (e.g. parse error / invalid request).
// https://modelcontextprotocol.io/specification/2025-11-25/basic#error-responses
// https://modelcontextprotocol.io/specification/2026-07-28/basic#error-responses
#[serde(default, skip_serializing_if = "Option::is_none")]
pub id: Option<RequestId>,
pub error: ErrorData,
Expand Down Expand Up @@ -1541,7 +1541,7 @@ macro_rules! paginated_result {
/// the server handler clears the field when responding to peers that
/// negotiated an older version.
///
/// [spec schema]: https://github.com/modelcontextprotocol/modelcontextprotocol/blob/5bed7b30527019e34ccb0eb474636651424501f6/schema/draft/schema.ts#L225-L234
/// [spec schema]: https://github.com/modelcontextprotocol/modelcontextprotocol/blob/271ecc9accafdd9b83a3c869fa67c22953b2af80/schema/2026-07-28/schema.ts#L219-L235
#[serde(default, skip_serializing_if = "Option::is_none")]
pub result_type: Option<ResultType>,
#[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")]
Expand Down Expand Up @@ -1699,7 +1699,7 @@ pub struct ReadResourceResult {
/// the server handler clears the field when responding to peers that
/// negotiated an older version.
///
/// [spec schema]: https://github.com/modelcontextprotocol/modelcontextprotocol/blob/5bed7b30527019e34ccb0eb474636651424501f6/schema/draft/schema.ts#L225-L234
/// [spec schema]: https://github.com/modelcontextprotocol/modelcontextprotocol/blob/271ecc9accafdd9b83a3c869fa67c22953b2af80/schema/2026-07-28/schema.ts#L219-L235
#[serde(default, skip_serializing_if = "Option::is_none")]
pub result_type: Option<ResultType>,
/// Time, in milliseconds, that this result may be treated as fresh (SEP-2549).
Expand Down Expand Up @@ -2065,7 +2065,7 @@ fn subscriptions_listen_request_meta_schema(
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[non_exhaustive]
pub struct SubscriptionsListenRequestParams {
/// Protocol-level metadata. Required by the draft wire schema.
/// Protocol-level metadata. Required by the 2026-07-28 wire schema.
#[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
#[cfg_attr(
feature = "schemars",
Expand Down Expand Up @@ -3300,7 +3300,7 @@ pub struct CompleteResult {
/// the server handler clears the field when responding to peers that
/// negotiated an older version.
///
/// [spec schema]: https://github.com/modelcontextprotocol/modelcontextprotocol/blob/5bed7b30527019e34ccb0eb474636651424501f6/schema/draft/schema.ts#L225-L234
/// [spec schema]: https://github.com/modelcontextprotocol/modelcontextprotocol/blob/271ecc9accafdd9b83a3c869fa67c22953b2af80/schema/2026-07-28/schema.ts#L219-L235
#[serde(default, skip_serializing_if = "Option::is_none")]
pub result_type: Option<ResultType>,
pub completion: CompletionInfo,
Expand Down Expand Up @@ -3781,7 +3781,7 @@ pub struct CallToolResult {
/// the server handler clears the field when responding to peers that
/// negotiated an older version.
///
/// [spec schema]: https://github.com/modelcontextprotocol/modelcontextprotocol/blob/5bed7b30527019e34ccb0eb474636651424501f6/schema/draft/schema.ts#L225-L234
/// [spec schema]: https://github.com/modelcontextprotocol/modelcontextprotocol/blob/271ecc9accafdd9b83a3c869fa67c22953b2af80/schema/2026-07-28/schema.ts#L219-L235
#[serde(default, skip_serializing_if = "Option::is_none")]
pub result_type: Option<ResultType>,
/// The content returned by the tool (text, images, etc.)
Expand Down Expand Up @@ -4169,7 +4169,7 @@ pub struct GetPromptResult {
/// the server handler clears the field when responding to peers that
/// negotiated an older version.
///
/// [spec schema]: https://github.com/modelcontextprotocol/modelcontextprotocol/blob/5bed7b30527019e34ccb0eb474636651424501f6/schema/draft/schema.ts#L225-L234
/// [spec schema]: https://github.com/modelcontextprotocol/modelcontextprotocol/blob/271ecc9accafdd9b83a3c869fa67c22953b2af80/schema/2026-07-28/schema.ts#L219-L235
#[serde(default, skip_serializing_if = "Option::is_none")]
pub result_type: Option<ResultType>,
#[serde(skip_serializing_if = "Option::is_none")]
Expand Down
17 changes: 8 additions & 9 deletions crates/rmcp/src/model/meta.rs
Original file line number Diff line number Diff line change
Expand Up @@ -367,7 +367,7 @@ impl schemars::JsonSchema for MetaObject {

fn json_schema(_: &mut schemars::SchemaGenerator) -> schemars::Schema {
schemars::json_schema!({
"description": "See [specification/draft/basic/index#general-fields] for notes on _meta usage.",
"description": "See [MCP general fields](https://modelcontextprotocol.io/specification/2026-07-28/basic#general-fields) for notes on _meta usage.",
"type": "object",
"additionalProperties": true,
})
Expand All @@ -383,10 +383,9 @@ impl schemars::JsonSchema for MetaObject {
/// - `io.modelcontextprotocol/clientCapabilities` (SEP-2575)
/// - `io.modelcontextprotocol/logLevel` (SEP-2575)
///
/// The 2026-07-28 draft schema marks the protocol-version, client-info, and
/// client-capabilities keys as required; earlier protocol versions do not know
/// them. All keys therefore stay optional at runtime and in the generated
/// (version-shared) JSON schema — use
/// The 2026-07-28 schema defines required per-request metadata; earlier
/// protocol versions do not know these keys. All keys therefore stay optional
/// at runtime and in the generated (version-shared) JSON schema — use
/// [`RequestMetaObject::missing_required_keys`] to validate a request against
/// the negotiated protocol version.
///
Expand All @@ -405,7 +404,7 @@ impl RequestMetaObject {
const META_KEY_CLIENT_CAPABILITIES: &str = "io.modelcontextprotocol/clientCapabilities";
const META_KEY_LOG_LEVEL: &str = "io.modelcontextprotocol/logLevel";

/// Request `_meta` keys the 2026-07-28 draft schema marks as required.
/// Request `_meta` keys validated for the 2026-07-28 protocol.
pub const DRAFT_REQUIRED_KEYS: [&str; 3] = [
Self::META_KEY_PROTOCOL_VERSION,
Self::META_KEY_CLIENT_INFO,
Expand Down Expand Up @@ -519,7 +518,7 @@ impl RequestMetaObject {
/// meta.missing_required_keys(&ProtocolVersion::V_2025_11_25)
/// .is_empty()
/// );
/// // The 2026-07-28 draft requires the SEP-2575 keys.
/// // The 2026-07-28 protocol requires per-request context.
/// assert_eq!(
/// meta.missing_required_keys(&ProtocolVersion::V_2026_07_28),
/// RequestMetaObject::DRAFT_REQUIRED_KEYS.to_vec(),
Expand Down Expand Up @@ -586,9 +585,9 @@ impl schemars::JsonSchema for RequestMetaObject {
let client_capabilities = generator.subschema_for::<ClientCapabilities>();
let log_level = generator.subschema_for::<LoggingLevel>();
// rmcp generates one schema shared by every supported protocol
// version, so the keys the 2026-07-28 draft marks as required are left
// version, so the keys validated for 2026-07-28 are left
// optional here: a 2025-11-25 request whose `_meta` only carries
// `progressToken` is valid. Draft-strict validation is available at
// `progressToken` is valid. Version-specific validation is available at
// runtime via [`RequestMetaObject::missing_required_keys`].
schemars::json_schema!({
"description": "Metadata reserved by MCP on requests. Extension keys are also allowed.",
Expand Down
Loading