This tutorial walks through building an MCP server in Rust with , 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.
Follow along and you'll have a working, registerable MCP server. 🦀 Why Rust for this?
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 — , , 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.
Three claims that don't hold, so nobody has to make them in the comments: 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:
1.
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.
2.
No shared interpreter.
These rigs install system-wide — no virtualenvs, by policy — so all sixteen share one Python.
Sixteen servers with independently drifting and 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 .
3.
The schema can't drift from the code.
More on this at Step 3, but it's the one that survives longest: 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.
How does this all fit together?
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 on the right-hand side is vLLM's own Rust frontend — the other article in this series.
This one is the on the left: the Rust that drives the box.
What is MCP, in one paragraph?
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.
Step 1 — Scaffold Now the dependencies.
Feature flags are the thing to get right here — on its own compiles fine and gives you almost nothing: Feature What it brings the trait and router types , , stdio transport The crate also ships , , , and more, all off by default.
Add them when you need them.
Then the rest: Resulting : 🔎 Tip: where the canonical examples live moves fast, and rendered docs lag.
The vendored tests on your own disk are compiled against the exact version you resolved: is a complete, working server in about 60 lines.
When an API question comes up, that file answers it faster and more reliably than anything else. ⚡ Step 2 — The server struct An r