Back to News & Insights
Artificial Intelligence August 16, 2026 ยท 9 min read

Build an MCP server in Rust with rmcp: a walk-through ๐Ÿฆ€

Step-by-step: scaffolding a real MCP server in Rust with the official rmcp SDK โ€” tools, JSON schemas, AWS calls, stdio transport, testing the protocol by hand, and wiring it into Claude Code.

Build an MCP server in Rust with rmcp: a walk-through ๐Ÿฆ€

This tutorial walks through building an MCP server in Rust with rmcp, the official Model Context Protocol Rust SDK.

The example is a real one: a devops agent that manages AWS EC2 G5g instances โ€” Graviton2 boxes with NVIDIA T4G GPUs โ€” serving Gemma 4 under vLLM. It launches instances, drives them over SSM, and health-checks the model. There's an existing Python version, so at the end we can put the two side by side.

Worth answering properly, because the weak version of the argument is easy to make and easy to demolish โ€” and the real one is better anyway.

Start with what it isn't: these tools are I/O bound. Every one is an AWS API call โ€” describeinstances, sendcommand, polling SSM โ€” so 100โ€“500 ms of network per call. The caller's language contributes nothing measurable there. Anyone selling you a Rust rewrite on raw speed for this workload is selling something.

| Claim | Why it fails | | --- | --- | | "462 ms startup is slow" | stdio servers spawn once per session, not per call | | "Rust is faster" | the work is network round-trips to AWS | | "smaller supply chain" | 241 crates vs 34 Python packages โ€” it's worse |

What actually justifies it, for this codebase: It's a fleet, not a server. This monorepo has 16 rigs, each with its own MCP server. That changes the units:

| All loaded together | ๐Ÿ Python | ๐Ÿฆ€ Rust | | --- | --- | --- | | Resident memory | 16 ร— 83 MB โ‰ˆ 1.33 GB | 16 ร— 12 MB โ‰ˆ 192 MB | | Session startup | 16 ร— 462 ms โ‰ˆ 7.4 s | 16 ร— 2.5 ms โ‰ˆ 40 ms |

A gigabyte of resident Python to expose sixteen tool lists is a real cost. No shared interpreter. These rigs install system-wide โ€” no virtualenvs, by policy โ€” so all sixteen share one Python. Sixteen servers with independently drifting boto3 and mcp pins in one interpreter is a standing conflict risk. A static binary has no such coupling; each rig pins whatever it likes in its own Cargo.lock. The schema can't drift from the code. More on this at Step 3, but it's the one that survives longest: schemars generates the tool schema from the same struct the handler destructures.

So: distribution and correctness, not speed. โœ… If you have one MCP server and it works, this is not a reason to rewrite it.

Two halves. The agent and the MCP server run on your machine; the GPU box is remote, and it has no inbound SSH โ€” everything goes through the AWS APIs.

The agent never talks to the GPU box directly. It calls a tool; the tool calls EC2 to manage the instance's lifecycle, or SSM Run Command to execute something on it. That's what lets the box run with no inbound rules at all โ€” which is the main reason this is worth building as a server rather than a pile of shell scripts.

The [RUST] on the right-hand side is vLLM's own Rust frontend โ€” the other article in this series. This one is the [RUST] on the left: the Rust that drives the box.

Model Context Protocol is how an AI agent discovers and calls your tools. Your server advertises a list of tools with JSON Schemas; the client (Claude Code, an IDE, whatever) calls them over JSON-RPC 2.0. Transport is usually stdio โ€” the client spawns your binary and talks over stdin/stdout.

That last detail matters for the Rust pitch: if the client spawns your process on every session, process startup is a user-visible cost.

Now the dependencies. Feature flags are the thing to get right here โ€” cargo add rmcp on its own compiles fine and gives you almost nothing:

| Feature | What it brings | | --- | --- | | server | the ServerHandler trait and router types | | macros | #[tool], #[toolrouter], #[toolhandler] | | transport-io | stdio transport |

The crate also ships client, auth, elicitation, transport-streamable-http-server and more, all off by default. Add them when you need them.

rmcp moves fast, and rendered docs lag. The vendored tests on your own disk are compiled against the exact version you resolved:

Want to discuss this further?

Book a free strategy call with our team to see how these insights apply to your specific business goals.

Book a consultation