RMCP: the official Rust SDK for the Model Context Protocol
The official Rust SDK for the Model Context Protocol
At a glance
- What is it?
- RMCP is the reference Rust implementation of MCP, tracking the 2026-07-28 spec while staying compatible with 2025-11-25. It is a good fit if you already run tokio and want macro-driven tool definitions; it is a poor fit if you need a synchronous runtime or a transport the crate does not ship.
- Who is it for?
- Adopt rmcp if you are building MCP servers or clients in Rust on tokio and want the tool, resource and prompt wiring generated by rmcp-macros rather than written by hand. Do not adopt it if you need a non-tokio runtime, or if you depend on a transport the crate does not list, since the README names stdio, child process and Streamable HTTP and nothing else.
- Can I use it commercially?
- Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
- Is it still maintained?
- Yes. The repository received new commits within the last day.
- What is it written in?
- Mainly Rust, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.
DEEP OPEN-SOURCE ANALYSIS
The gap RMCP fills: MCP without hand-written JSON-RPC plumbing
The Model Context Protocol defines how a client discovers and calls tools, reads resources, fetches prompts, and exchanges sampling and elicitation messages with a server. Implementing that by hand in Rust means writing JSON-RPC framing, capability negotiation, schema generation and request routing before you write a single line of application logic. RMCP is the official Rust SDK for that protocol, and the README frames it as an implementation of the stable 2026-07-28 specification that remains compatible with 2025-11-25 and earlier releases. The audience is Rust developers who already build on tokio, because the README states the SDK uses the tokio async runtime and lists tokio and serde as its basic dependencies, with schemars for JSON Schema 2020-12 generation. If your codebase is a synchronous Rust service, or one built on a different async executor, the crate's core assumption does not match your code, and that is a structural mismatch rather than a configuration detail.
Two crates, one macro layer, and where the protocol logic lives
The repository splits into rmcp, described as the core crate providing the protocol implementation, and rmcp-macros, a procedural macro crate that generates tool implementations. That split is the architecture in miniature: the macros do not implement protocol behaviour, they generate the boilerplate that registers your functions with the runtime. On the server side the README names three attributes, #[tool], #[tool_router] and #[tool_handler], and states that for a tools-only server #[tool_router(server_handler)] lets you skip a separate ServerHandler impl entirely. The data flow is conventional MCP. A client sends list_tools, the server returns each tool's name, description and a JSON Schema for its parameters, and the client later sends call_tool. Parameter schemas come from schemars deriving JsonSchema on a struct. The example defines AddParams with two i32 fields, takes it as Parameters<AddParams>, and returns a String. Nothing in the README suggests the macro layer inspects your function body, so validation of arguments beyond the generated schema is still your responsibility.
Client lifecycle: serve() versus the discover handshake
This is the part of the README that most repays a careful read, because it describes a behavioural fork rather than a convenience method. serve() uses what the README calls the legacy MCP lifecycle: the client sends initialize, receives negotiated server information, then sends notifications/initialized. ClientServiceExt::serve_with_lifecycle selects a different path. ClientLifecycleMode::Discover starts directly with server/discover and, per the README, includes client metadata on every request; discovery completes startup and no notifications/initialized is sent, with each subsequent request carrying protocol version, client information and capabilities in _meta. ClientLifecycleMode::Auto probes the discover lifecycle and falls back when a legacy server reports that server/discover is not implemented or does not respond within 10 seconds. That ten second figure is a fixed constant stated in the README, not something the surrounding text describes as configurable. ClientLifecycleMode::Initialize is documented as equivalent to the existing serve() behaviour. If you are upgrading an existing client, the default has not silently changed, but choosing Auto introduces a startup delay bounded by that timeout against servers that do not implement discovery.
Getting a tools-only server running
The README gives the install command as cargo add rmcp --features server, and notes a dev channel variant that adds --git https://github.com/modelcontextprotocol/rust-sdk --branch main. The feature flag matters: the server feature is what the README's own instructions enable, so a dependency added without features will not match the examples. A minimal tools-only server follows the README example closely. Derive Debug, serde::Deserialize and schemars::JsonSchema on a parameter struct. Derive Clone on the service struct. Annotate the impl block with #[tool_router(server_handler)] and each method with #[tool(description = "...")]. Start it with Calculator.serve(stdio()).await?, where stdio() is the transport, then call service.waiting().await to block until shutdown. For a server that needs more than tools, the README points at ServerHandler and ClientHandler as the traits to implement, and shows a transport built from tokio::io::{stdin, stdout} as a tuple. The README also lists an examples directory and a Development section, though the supplied material does not include their contents, so treat those as pointers rather than documented instructions.
What the 2026-07-28 spec adds, and what that costs you
The README enumerates the features introduced in 2026-07-28: server discovery and negotiation, transport-neutral subscriptions, long-running tasks, response caching, multi-round-trip requests and standard HTTP routing headers. Each of those is a section in the table of contents, which means the SDK surface is broader than tools, resources and prompts. That breadth is the trade-off. A server that only exposes tools still compiles against a crate whose documentation covers subscriptions, tasks, caching and pagination, and the compatibility promise cuts both ways: the README says the SDK implements 2026-07-28 while remaining fully compatible with 2025-11-25 and earlier, so behaviour depends on what the peer negotiates rather than on what you wrote. The README does not spell out per-feature fallback semantics for every one of those capabilities in the material available here. If your server advertises a capability that an older client cannot use, verifying the negotiation outcome is on you, not on the SDK documentation as presented.
Where RMCP is the wrong choice
The transport list is the sharpest limitation. The README's transports section, the client example using TokioChildProcess with a Command, and the server example using stdio() together indicate stdio, child process and Streamable HTTP, including a stateless variant. If your deployment needs a transport outside that set, the SDK does not offer it and you would be writing the transport layer yourself against the core protocol types. The second constraint is the runtime. The README states tokio explicitly and lists it as a basic dependency, so this is not an executor-agnostic library. The third is version drift. The README links a migration guide for 3.x at discussions/969 and describes breaking changes, and the release list shows 3.3.0 and 3.2.0 landing within about ten days of each other. A crate publishing minor versions that quickly on a protocol still gaining features means pinning matters more than usual. Finally, the repository metadata reports the licence as NOASSERTION. That is a signal to open the LICENSE file yourself before you ship, not a statement about what the licence is.
Alternatives and the actual difference in approach
The clearest alternative is writing your own MCP layer directly against the specification at modelcontextprotocol.io, using serde for message types and tokio for I/O. The difference is not effort in the abstract, it is where the generated code lives. RMCP puts tool registration, parameter schema derivation and request routing behind rmcp-macros, so a tool is a method with an attribute and the dispatch table is produced at compile time. A hand-rolled implementation puts that dispatch in your source, which is more code but also more visible: you decide how a malformed call_tool argument is rejected, how capabilities are advertised, and which protocol version you claim. The other alternative is using an MCP SDK in a different language and calling into it, which avoids the tokio constraint entirely at the cost of a process boundary. The README also lists Related Projects, which the supplied material does not expand, so I cannot compare those directly. Choose RMCP when the macro-generated wiring matches how you already write Rust services; choose hand-rolling when you need a transport or runtime the crate does not cover, since in that case you are writing the transport anyway and the macro layer saves you less than it appears to.
Maintenance, upgrades and licence checks before you commit
The upgrade path is documented but not automatic. The README points 3.x migrators at a migration guide in GitHub discussions, and the release cadence shown in the repository metadata (3.3.0 on 2026-09-10, 3.2.0 on 2026-08-31) suggests you should expect to read that guide more than once. The practical cost is that rmcp and rmcp-macros version together, both at 3.3.0 in the latest release listed, so a partial upgrade is not the intended path. On licensing, the repository metadata says NOASSERTION, which is not a licence identifier, so the only reliable source is the LICENSE file the README's badge links to. I am not going to characterise what that file says, because the supplied material does not include it, and this is not legal advice in any case. The concrete pre-adoption checklist is short: read the migration guide at discussions/969, confirm the resolved rmcp version in your Cargo.lock, check that the server feature flag is enabled in your Cargo.toml, and open LICENSE before you distribute anything built on it.
Editorial conclusion
Adopt rmcp if you are building MCP servers or clients in Rust on tokio and want the tool, resource and prompt wiring generated by rmcp-macros rather than written by hand. Do not adopt it if you need a non-tokio runtime, or if you depend on a transport the crate does not list, since the README names stdio, child process and Streamable HTTP and nothing else. Before committing, read the 3.x migration guide at discussions/969, confirm which rmcp version your Cargo.lock resolves to, and read the LICENSE file directly, because the repository metadata reports NOASSERTION rather than a recognised SPDX identifier.
Community notes