From 46c5710311dbfdcf0ed65b34e21062a1da719690 Mon Sep 17 00:00:00 2001 From: Alex Hancock Date: Thu, 30 Jul 2026 15:32:59 -0400 Subject: [PATCH] docs: complete Tier 1 feature docs and finalize roadmap --- README.md | 79 +++++++++++++++++++++++++++++++++++++++++++++----- ROADMAP.md | 85 ++++++++++++++++++++++++++++++++---------------------- 2 files changed, 121 insertions(+), 43 deletions(-) diff --git a/README.md b/README.md index da7019f37..89eb60a8e 100644 --- a/README.md +++ b/README.md @@ -269,7 +269,8 @@ use rmcp::model::{CallToolResult, ContentBlock, ResourceContents}; #[tool(description = "Render a chart")] async fn chart(&self) -> Result { - let png_base64 = render_png(); // base64-encoded bytes + let png_base64 = render_png(); // base64-encoded image bytes + let wav_base64 = render_wav(); // base64-encoded audio bytes Ok(CallToolResult::success(vec![ // Text @@ -277,7 +278,7 @@ async fn chart(&self) -> Result { // Image — base64 data + MIME type ContentBlock::image(png_base64, "image/png"), // Audio — base64 data + MIME type - // ContentBlock::audio(wav_base64, "audio/wav"), + ContentBlock::audio(wav_base64, "audio/wav"), // Embedded resource — inline text (or ResourceContents::blob for binary) ContentBlock::resource(ResourceContents::text( "chart source data", @@ -286,6 +287,7 @@ async fn chart(&self) -> Result { ])) } # fn render_png() -> String { String::new() } +# fn render_wav() -> String { String::new() } ``` Image and audio data are base64 strings with a MIME type. For embedded @@ -412,6 +414,18 @@ impl ServerHandler for MyServer { .with_mime_type("image/png"), ])) } + // Template-expanded URI — the client fills in `{user_id}` from the + // `users://{user_id}/profile` template declared in + // `list_resource_templates`, and the server reads the concrete URI. + uri if uri.starts_with("users://") && uri.ends_with("/profile") => { + let user_id = uri + .trim_start_matches("users://") + .trim_end_matches("/profile"); + Ok(ReadResourceResult::new(vec![ResourceContents::text( + format!(r#"{{"id": "{user_id}", "name": "User {user_id}"}}"#), + uri, + )])) + } _ => Err(McpError::resource_not_found( "resource_not_found", Some(json!({ "uri": request.uri })), @@ -424,8 +438,12 @@ impl ServerHandler for MyServer { _request: Option, _context: RequestContext, ) -> Result { + // Declare a URI template with a `{user_id}` parameter. Clients expand it + // (e.g. `users://42/profile`) and pass the concrete URI to `read_resource`. Ok(ListResourceTemplatesResult { - resource_templates: vec![], + resource_templates: vec![ + ResourceTemplate::new("users://{user_id}/profile", "user-profile"), + ], next_cursor: None, meta: None, }) @@ -446,8 +464,12 @@ let result = client.read_resource( ReadResourceRequestParams::new("file:///config.json"), ).await?; -// List resource templates +// List resource templates, then read a resource through one by expanding its +// parameters into a concrete URI (`users://{user_id}/profile` → `users://42/profile`). let templates = client.list_all_resource_templates().await?; +let profile = client.read_resource( + ReadResourceRequestParams::new("users://42/profile"), +).await?; ``` ### Notifications @@ -1000,6 +1022,7 @@ impl ServerHandler for MyServer { _context: RequestContext, ) -> Result { let values = match &request.r#ref { + // Completion for a prompt argument (`ref/prompt`). Reference::Prompt(prompt_ref) if prompt_ref.name == "sql_query" => { match request.argument.name.as_str() { "operation" => vec!["SELECT", "INSERT", "UPDATE", "DELETE"], @@ -1020,6 +1043,17 @@ impl ServerHandler for MyServer { _ => vec![], } } + // Completion for a resource-template argument (`ref/resource`). The + // `uri` identifies the template (e.g. `users://{user_id}/profile`) + // and `argument.name` is the template variable being completed. + Reference::Resource(resource_ref) + if resource_ref.uri == "users://{user_id}/profile" => + { + match request.argument.name.as_str() { + "user_id" => vec!["1", "2", "42"], + _ => vec![], + } + } _ => vec![], }; @@ -1041,12 +1075,22 @@ impl ServerHandler for MyServer { ```rust use rmcp::model::*; +// Completion for a prompt argument. let result = client.complete(CompleteRequestParams::new( Reference::for_prompt("sql_query"), ArgumentInfo::new("operation", "SEL"), )).await?; // result.completion.values contains suggestions like ["SELECT"] + +// Completion for a resource-template argument: reference the template by URI +// and complete one of its variables (`user_id`). +let resource_completion = client.complete(CompleteRequestParams::new( + Reference::for_resource("users://{user_id}/profile"), + ArgumentInfo::new("user_id", "4"), +)).await?; + +// resource_completion.completion.values contains suggestions like ["42"] ``` **Example:** [`examples/servers/src/completion_stdio.rs`](examples/servers/src/completion_stdio.rs) @@ -1531,7 +1575,7 @@ let transport = StreamableHttpClientTransport::from_uri("http://localhost:8000/m let client = ClientInfo::default().serve(transport).await?; ``` -#### A note on SSE +#### Server-Sent Events (SSE) Streamable HTTP responses arrive as either a single `application/json` body or a `text/event-stream` (Server-Sent Events) stream when the server pushes @@ -1539,9 +1583,28 @@ notifications or requests before the result. `rmcp` handles both automatically (SSE parsing lives behind the `client-side-sse` feature). There is no separate "SSE transport" to configure — it's an implementation detail of Streamable HTTP. -> The standalone HTTP+SSE transport from `2024-11-05` is superseded by Streamable -> HTTP. For server-to-client streaming under `2026-07-28`, see -> [Subscriptions](#subscriptions). +#### Legacy HTTP+SSE transport (`2024-11-05`) — intentionally not provided + +The standalone two-endpoint **HTTP+SSE transport** defined in protocol revision +`2024-11-05` (a separate `GET` SSE channel plus a `POST` message endpoint) is a +**deliberate non-goal** for `rmcp`. It was [replaced by Streamable HTTP in the +`2025-03-26` revision](https://modelcontextprotocol.io/specification/2026-07-28/basic/transports), +and `rmcp` targets current spec revisions (`2025-11-25` and `2026-07-28`), so it +ships **no legacy HTTP+SSE client or server transport**. + +What to use instead: + +- **New client/server code** — use [Streamable HTTP](#streamable-http). It carries + the same SSE streaming semantics over a single endpoint and is the transport all + supported spec revisions expect. +- **Server-to-client streaming** (push notifications, resource updates) — this is + built into Streamable HTTP; see [Subscriptions](#subscriptions). +- **Talking to a legacy `2024-11-05`-only server** — front it with a proxy that + speaks Streamable HTTP, or pin a dependency to a release that predates the + transport's removal. `rmcp` will not add the legacy transport back. + +This is a supported-surface decision, not a missing feature: every transport +`rmcp` implements is listed in the [Transports](#transports) table above. --- diff --git a/ROADMAP.md b/ROADMAP.md index c3a00376e..27679a1c8 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -2,9 +2,24 @@ This roadmap tracks the path to [SEP-1730](https://github.com/modelcontextprotocol/modelcontextprotocol/issues/1730) Tier 1 for the Rust MCP SDK. -**Status (2026-07-29):** conformance is 100% across every date-versioned suite, and -the stable **v3.0.0** release has shipped. The remaining Tier 1 work is documentation -coverage and two governance documents. +**Status (2026-07-30): all SEP-1730 Tier 1 requirements are met.** Conformance is +100% across every date-versioned suite, the stable **v3.0.1** release has shipped, +issue triage and critical-bug (P0) resolution are within the Tier 1 SLAs, the +governance documents (`VERSIONING.md`, `DEPENDENCY_POLICY.md`, this `ROADMAP.md`) are +published, and all 48 non-experimental features are documented with examples. This +document now serves as the ongoing tracker for spec conformance and SDK health. + +| SEP-1730 Tier 1 requirement | Status | Evidence | +| --------------------------------------------------- | ------ | -------- | +| Server conformance 100% (date-versioned) | ✅ | 30/30 — see below | +| Client conformance 100% (date-versioned) | ✅ | 39/39 scored — see below | +| Issue triage ≥90% within 2 business days | ✅ | 95.2% (20/21) | +| All P0 bugs resolved within 7 days | ✅ | 0 open; last P0 (#741) resolved in 3 days | +| Stable release ≥1.0.0 (no pre-release suffix) | ✅ | `rmcp-v3.0.1` (see tooling note below) | +| Clear versioning + breaking-change policy | ✅ | [`VERSIONING.md`](VERSIONING.md) | +| All non-experimental features documented w/ examples| ✅ | 48/48 in [`README.md`](README.md) | +| Published dependency update policy | ✅ | [`DEPENDENCY_POLICY.md`](DEPENDENCY_POLICY.md) + [`.github/dependabot.yml`](.github/dependabot.yml) | +| Published roadmap tracking spec components | ✅ | this document | | Suite (date-versioned) | Server | Client | | ---------------------- | ------------- | ------------- | @@ -14,6 +29,12 @@ coverage and two governance documents. Only date-versioned scenarios count toward SDK tiering. `draft` (2026-07-28 draft) and `extension` scenarios are informational and reported separately below. +> **Tooling note — `stable_release`:** the SEP-1730 `tier-check` CLI may report +> `stable_release` as failing because it does not parse the workspace tag prefix +> `rmcp-v` (as in `rmcp-v3.0.1`). `rmcp-v3.0.1` is a genuine stable, non-pre-release +> release ([Releases](https://github.com/modelcontextprotocol/rust-sdk/releases)); the +> flag is a tooling artifact, not an unmet requirement. + --- ## Conformance @@ -49,48 +70,42 @@ the milestone: --- -## Tier 1 — remaining work - -Conformance, stable release, labels, issue triage, and spec-tracking already meet the -Tier 1 bar. What's left: - -### Documentation (Tier 1 requires all non-experimental features documented with examples) - -The README now documents core primitives comprehensively with linked examples. - -### Governance & Policy - -- [ ] Add `VERSIONING.md` — document the semver scheme, what constitutes a breaking - change, and how breaking changes are communicated (migration guides are linked - from the README but the policy itself is not yet written down). -- [ ] Add `DEPENDENCY_POLICY.md` — a published dependency update policy (Dependabot is - configured in `.github/dependabot.yml`, but Tier 1 requires a written, findable policy). -- [ ] Re-triage mislabeled `P0` issues — #869 / #871 / #872 are SEP *feature* - implementation tasks, not critical bugs; they should not carry `P0`. Reserving - `P0` for genuine critical bugs keeps the SEP-1730 critical-bug-resolution metric - accurate. - -### Nice-to-have (scorecard hygiene) - -- [ ] Add a top-level `CHANGELOG.md` (release notes are currently managed by release-plz). -- [ ] Add a top-level `CONTRIBUTING.md` (contributor docs currently live at `docs/CONTRIBUTE.MD`). - ---- - ## Completed +### Tier 1 requirements + - [x] **v3.0.0 stable released** (2026-07-28) — MRTR, SEP-2549 cache hints, SEP-2243 - standard headers, SEP-2575 stateless MCP, and SEP-2106 relaxations + standard headers, SEP-2575 stateless MCP, and SEP-2106 relaxations; **v3.0.1** + is the current stable release - [x] 2025-11-25 server conformance 100% (30/30) - [x] 2025-11-25 client conformance 100% - [x] 2026-07-28 server conformance 100% (30/30 dated) - [x] 2026-07-28 client conformance 100% (dated) +- [x] Issue triage ≥90% within 2 business days (95.2%, 20/21) with the full SEP-1730 + label taxonomy (bug, enhancement, question, needs confirmation, needs repro, + ready for work, good first issue, help wanted, P0–P3) +- [x] All P0 bugs resolved within 7 days (0 open; #741 resolved in 3 days). #815 was + reclassified from `P0` to `T-security` — it was a CVE/advisory-coordination task + for an already-shipped fix (PR #764, released in v1.4.0), not a critical-bug fix +- [x] `VERSIONING.md` — semver scheme, breaking-change definition, and communication policy +- [x] `DEPENDENCY_POLICY.md` — published dependency update policy (with `.github/dependabot.yml`) +- [x] `SECURITY.md` and Dependabot configuration +- [x] All 48 non-experimental features documented with examples in the README + (closed the last 6 gaps on 2026-07-30: audio results, resource-template reading, + resource-argument completion, ping, and the legacy HTTP+SSE non-goal writeup) + +### Spec implementation + - [x] SEP-2322 MRTR (server scenarios + `sep-2322-client-request-state`) - [x] SEP-2575 Make MCP Stateless (`server-stateless`) - [x] SEP-2164 resource not found - [x] SEP-2549 cache hints (`caching`) - [x] SEP-2243 HTTP standardization (`http-header-validation`, standard headers) - [x] DNS rebinding protection -- [x] Full SEP-1730 issue-triage label taxonomy (bug, enhancement, question, - needs confirmation, needs repro, ready for work, good first issue, help wanted, P0–P3) -- [x] `SECURITY.md` and Dependabot configuration + +--- + +## Nice-to-have (scorecard hygiene, not required for Tier 1) + +- [ ] Add a top-level `CHANGELOG.md` (release notes are currently managed by release-plz). +- [ ] Add a top-level `CONTRIBUTING.md` (contributor docs currently live at `docs/CONTRIBUTE.MD`).