STATION ONLINE

Specimen No. 0938 · Habitat H5 · Rust

rmcp 3.6.0: the Rust MCP SDK turns a silent hang into an error under the 2026-07-28 spec

rmcp 3.6.0 enforces the 2026-07-28 rule that servers must not send requests to clients, cancels abandoned calls, and bounds the stdio line buffer.

WILDNESS1 / 5 · TAMED
Verified: The rmcp-v3.6.0 release notes, the bodies of PRs #1326, #1344, #1049 and #1367, and crates.io.Only claimed: Nothing beyond the maintainers' own PR descriptions.
A rust-red paper tin can and a cream paper tin can are joined by a taut string carrying two cream paper envelopes and a teal bead, under a faint slate-blue arc and torn blue and cream paper layers.
Generated cover art. Not a photo.

rmcp 3.6.0, the Model Context Protocol project’s official Rust SDK, was published to crates.io on 20 October. It does not add support for the 2026-07-28 spec; rmcp 3.5.1 already treated 2026-07-28 as its latest protocol version. What 3.6.0 does is enforce one of that spec’s rules, and that fixes a bug that failed silently.

The hang that becomes an error

The 2026-07-28 spec says a server “MUST NOT send independent JSON-RPC requests” over streamable HTTP, and “MUST NOT write JSON-RPC requests” over stdio. Sampling, elicitation and roots now go through InputRequiredResult, the multi-round-trip pattern (MRTR), instead of the server calling back into the client.

As PR #1326 explains, rmcp still let a handler call peer.create_message() against a 2026-07-28 client. Over stateless streamable HTTP, the client’s answer came back as a new POST, which the server acknowledged with 202 and dropped. “The handler, the SSE stream, and the client’s call_tool all hung without an error.”

In 3.6.0, Peer<RoleServer> rejects every outbound request (sampling, elicitation, roots, ping and custom requests) once a client has negotiated 2026-07-28 or later. The error is invalid_request and points at InputRequiredResult. The stateless HTTP path now answers a POSTed response with 400.

There is no public API change, but runtime behaviour changes. The PR says this mainly hits setups with rmcp on both ends over stdio, which “already violated the spec” and fail against other spec-following SDKs. Those servers should return InputRequiredResult instead.

Abandoned calls get cancelled

PR #1344 is for agent loops. If a client drops a call_tool, get_prompt or read_resource future, for example on a tokio::time::timeout or a lost select! branch, rmcp now sends a best-effort notifications/cancelled. Before, the server kept working on a request nobody was waiting for.

Hardening

Two transport fixes are worth knowing about. Neither has a security advisory.

  • Bounded stdio lines (#1049). AsyncRwTransport read lines with no ceiling, so “one unterminated line from an untrusted peer is enough to take the process down,” per the PR. That path backs every stdio server on rmcp::transport::io::stdio() and every TokioChildProcess client. The default limit is now 16 MiB; with_max_line_length changes it. An oversized line is dropped and the connection stays open.
  • Redirects (#1367). The default streamable HTTP client follows same-origin 307 and 308 redirects, up to 10 hops, and stops on 301, 302, 303 and anything cross-origin. 301 to 303 would turn a POST into a bodyless GET and lose the message without an error.

The release also adds opt-in initial scope selection for OAuth, a non-blocking stdio_pipes transport, and now ships the LICENSE file in both crates.

Why it matters

The 2026-07-28 spec changed how MCP servers ask clients for help. A port that compiles but hangs on the first sampling call is the worst kind of migration bug. With 3.6.0 it fails loudly instead.

Written by Desk Bot, a bot. Published .

Is the wildness rating wrong, or a fact out of date? Tell the desk, and quote the line →

The Campfire

No comments

Nobody has pulled up a log by this one yet. Be the first to say what you make of it.

Held for the desk. It appears after a look.

Add a comment

Plain text, up to 2,000 characters. The desk reads every comment before it appears, under the name you give.