MCPの公式Rust SDK(rmcp)でHello World
RustにはMCPサーバー用の公式SDKがあります。
このリポジトリのREADME.mdによると、現在(2025/07/02)はファーストリリースが行われていません。
Usage
を見るとrmcp
というクレート名で使えるようです。
crates.ioでrmcp
を検索したところ、以下のページが見つかりました。
このページの記述内容は前述の公式SDKのリポジトリとそっくりですが、Repositoryのリンクが異なります。
リンク先のhttps://github.com/4t145/rmcp/を見ると、このリポジトリの内容が公式SDKに統合される予定のようです。
This crate was merged into official sdk. We will continue our development there.
また、公式リポジトリのIssueを見ると、リリース作業が進行中であることがわかります。
現在の実装とほとんど変わらずリリースされる雰囲気に見えます。
そこで、リリースより一足先に公式SDKを使ってみました。
公式のサンプルコード
公式SDKにはサンプルコードがいくつか用意されています。
サーバーとクライアントでサンプルコードのディレクトリが分かれています。
$ git clone https://github.com/modelcontextprotocol/rust-sdk.git
# サーバーのサンプルコードがあるディレクトリ
$ cd ./examples/servers
リポジトリをcloneしてビルドしてみると、正常にコンパイルできました。
ただしOpenSSLがインストールされていない場合はビルドに失敗します。
そこで、Docker上でビルドできる環境を整えたリポジトリを作成しました。
ビルド用スクリプトも用意してありますので、サンプルを手軽に動かしたい場合はREADMEを参考にしてください。
実装
ここからは、上記サンプルを参考にrmcpで簡単なMCPサーバーを作成します。
最終的には、以下のリポジトリと同じ内容になります。
手順
# プロジェクト作成
$ cargo new rmcp-hello-world
$ cd rmcp-hello-world
# サンプルコード作成(ファイル内容は後述)
$ vi src/main.rs
$ vi Cargo.toml
# Docker利用時(ファイル内容は後述)
$ vi Dockerfile
$ vi build.sh
$ chmod +x build.sh
# ビルド実行
$ ./build.sh
# もしくはローカル環境で
# cargo build --release
# バイナリ生成確認
$ ls target/release/rmcp-hello-world
以下はサンプルコードの内容です。
Cargo.toml
[package]
name = "rmcp-hello-world"
version = "0.1.0"
edition = "2024"
publish = false
[dependencies]
rmcp = { git = "https://github.com/modelcontextprotocol/rust-sdk.git", rev = "8a577659f01917289064c0a3c753392b44305ef4", features = [
"server",
"transport-io",
] }
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }
serde = { version = "1.0", features = ["derive"] }
anyhow = "1.0"
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = [
"env-filter",
"std",
"fmt",
] }
schemars = "0.8"
src/main.rs
use rmcp::{ServiceExt, transport::stdio, ServerHandler, model::*, tool, schemars};
use serde::Deserialize;
use tracing_subscriber::{self, EnvFilter};
#[derive(Debug, Deserialize, schemars::JsonSchema)]
pub struct HelloRequest {
pub name: String,
}
#[derive(Clone)]
pub struct HelloTool;
#[tool(tool_box)]
impl HelloTool {
#[tool(description = "Say hello world")]
pub async fn hello_world(&self) -> Result<CallToolResult, rmcp::Error> {
Ok(CallToolResult::success(vec![Content::text("Hello, world!".to_string())]))
}
#[tool(description = "Say hello to someone")]
pub async fn hello(&self, #[tool(aggr)] req: HelloRequest) -> Result<CallToolResult, rmcp::Error> {
Ok(CallToolResult::success(vec![Content::text(format!("Hello, {}", req.name))]))
}
}
#[tool(tool_box)]
impl ServerHandler for HelloTool {
fn get_info(&self) -> ServerInfo {
ServerInfo {
protocol_version: ProtocolVersion::V_2024_11_05,
capabilities: ServerCapabilities::builder().enable_tools().build(),
server_info: Implementation::from_build_env(),
instructions: Some("This server provides 'hello_world' and 'hello' tools.".to_string()),
}
}
}
#[tokio::main]
async fn main() -> anyhow::Result<()> {
tracing_subscriber::fmt()
.with_env_filter(EnvFilter::from_default_env().add_directive(tracing::Level::DEBUG.into()))
.with_writer(std::io::stderr)
.with_ansi(false)
.init();
tracing::info!("Starting Hello MCP server");
let service = HelloTool.serve(stdio()).await.inspect_err(|e| {
tracing::error!("serving error: {:?}", e);
})?;
service.waiting().await?;
Ok(())
}
Dockerfile
FROM rust:latest
# Install Dependencies
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
pkg-config \
libssl-dev \
bash \
git \
&& rm -rf /var/lib/apt/lists/*
ARG USER_NAME=rustuser
ARG USER_ID=1000
ARG GROUP_ID=1000
RUN groupadd -g ${GROUP_ID} ${USER_NAME} \
&& useradd -m -u ${USER_ID} -g ${USER_NAME} ${USER_NAME}
WORKDIR /workspace
USER ${USER_NAME}
CMD ["/bin/bash"]
build.sh
#!/bin/sh
docker build -t rust-dev .
docker run --rm -v "$(pwd)":/workspace rust-dev cargo build --release
# ./target/release/rmcp-hello-world
動作確認
MCPサーバーの動作確認にはMCP Inspectorを使うと便利です。
MCP Inspectorを使うことで、AIエージェントの代わりにブラウザ上からMCPサーバーへアクセスし、動作確認ができます。
起動コマンド例は以下の通りです。
$ npx @modelcontextprotocol/inspector
Need to install the following packages:
@modelcontextprotocol/inspector@0.15.0
Ok to proceed? (y)
Starting MCP inspector...
⚙️ Proxy server listening on 127.0.0.1:6277
🔑 Session token: 99f3b3f167d34e7f21b6d9bc5e4a7f120f7674a3f788e57cd921f3011d119045
Use this token to authenticate requests or set DANGEROUSLY_OMIT_AUTH=true to disable auth
🔗 Open inspector with token pre-filled:
http://localhost:6274/?MCP_PROXY_AUTH_TOKEN=99f3b3f167d34e7f21b6d9bc5e4a7f120f7674a3f788e57cd921f3011d119045
🔍 MCP Inspector is up and running at http://127.0.0.1:6274 🚀
表示されたトークン付きURL(例: http://localhost:6274/?MCP_PROXY_AUTH_TOKEN=...
)にブラウザでアクセスすると、MCP Inspectorの画面が開きます。
MCPサーバーに接続する
ブラウザ上で以下の設定を入力します。
- Transport Type:
STDIO
- Command: ビルドしたバイナリファイルへの絶対パス(例:
/home/user/git/rmcp-hello-world/target/release/rmcp-hello-world
)
Connect
ボタンをクリックするとMCPサーバーに接続されます。
成功するとTools
欄にList Tools
ボタンが表示されます。
Tools
hello
hello
を選択すると右側にname
欄が表示されます。
name
欄に任意の文字列を入力し、Run Tool
ボタンをクリックするとHello,
というレスポンスが得られます。
hello_world
hello_world
は入力欄がなく、Run Tool
ボタンをクリックするとHello, world!
というレスポンスが返ります。
サンプルコードの解説
Cargo.toml
rmcp
はGitHubリポジトリとコミットハッシュを指定しています。
[dependencies]
rmcp = { git = "https://github.com/modelcontextprotocol/rust-sdk.git", rev = "8a577659f01917289064c0a3c753392b44305ef4", features = [
"server",
"transport-io",
] }
これはmainブランチの実装が変わってもサンプルコードが動作することを保証するためです。
src/main.rs
use rmcp::{ServiceExt, transport::stdio, ServerHandler, model::*, tool, schemars};
#[derive(Debug, Deserialize, schemars::JsonSchema)]
pub struct HelloRequest {
pub name: String,
}
#[derive(Clone)]
pub struct HelloTool;
#[tool(tool_box)]
impl HelloTool {
#[tool(description = "Say hello world")]
pub async fn hello_world(&self) -> Result<CallToolResult, rmcp::Error> {
Ok(CallToolResult::success(vec![Content::text("Hello, world!".to_string())]))
}
#[tool(description = "Say hello to someone")]
pub async fn hello(&self, #[tool(aggr)] req: HelloRequest) -> Result<CallToolResult, rmcp::Error> {
Ok(CallToolResult::success(vec![Content::text(format!("Hello, {}", req.name))]))
}
}
#[tool(tool_box)]
impl ServerHandler for HelloTool {
fn get_info(&self) -> ServerInfo {
ServerInfo {
protocol_version: ProtocolVersion::V_2024_11_05,
capabilities: ServerCapabilities::builder().enable_tools().build(),
server_info: Implementation::from_build_env(),
instructions: Some("This server provides 'hello_world' and 'hello' tools.".to_string()),
}
}
}
impl HelloTool
内にMCPサーバーの機能を実装しています。
#[tool(tool_box)]
を付与することでToolとして必要な実装が自動で追加されます。
各メソッドに#[tool]
を付けることでToolとして公開されます。
fn hello
は引数を受け取り、(&self, #[tool(aggr)] req: HelloRequest)
の形でリクエスト内の引数を受け取れます。
#[tokio::main]
async fn main() -> anyhow::Result<()> {
// --snip--
let service = HelloTool.serve(stdio()).await.inspect_err(|e| {
tracing::error!("serving error: {:?}", e);
})?;
service.waiting().await?;
Ok(())
}
main関数ではMCPサービスの起動処理を行っています。
その他のサンプル
最後に、私がRustのコーディング時に使うために自作したMCPサーバーを紹介します。
よければ参考にしてください。
Discussion