Open7
MCPのRust用SDKのexampleであるcounter-serverをstdioやSSEで叩いてみる

1. Claude Desktopからstdioで接続
MCPサーバーのrust-sdkのexampleとして実装されているcounter-server
を、先ずはClaude Desktopから叩いてみて様子を見たい。
counter-server
は単純に数字の加算減算と現在の数字の確認ができるツール。

コンテナでMCPサーバーを立ち上げたいので、上記のリポジトリをforkした上で、ルートディレクトリにDockerfileを追加。
FROM rust:1.85 AS builder
WORKDIR /app
COPY . .
RUN cargo build --release --example counter-server
FROM debian:bookworm-slim
RUN apt-get update && apt-get install -y --no-install-recommends ca-certificates \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY /app/target/release/examples/counter-server ./counter-server
USER root
CMD ["./counter-server"]
ビルドする。
docker build -t mcp/counter-server:latest .

MCPのクライアントであるClaude Desktopの claude_desktop_config.json
は以下のように記述。
dockerコンテナは -i
を付けてインタラクティブモードで立ち上げる。(Claude DesktopはデフォルトでMCPサーバーとstdioで会話する仕様である様子)
{
"mcpServers": {
"counter-server": {
"command": "docker",
"args": [
"run",
"-i",
"--rm",
"mcp/counter-server"
]
}
}
}

Claude Desktopを立ち上げると counter-server
と接続できていることが確認できる。
以下の通りカウントの加算減算をお願いしつつ、現在の数値を取得できることを確認。

counter-server
をwebサーバーとして起動してServer-Sent-Eventsで接続
2. 上記と同じく、rust-sdkのリポジトリに用意されているexampleのコードを利用する。
actix-web
でWebサーバーとして起動するコードがあったのでこれを利用。
cargo run --example actix_web

README.mdによると cargo run --example sse
するだけで挙動を確かめられそうではあったが、エラーが出たため examples/clients/src/sse.rs
を以下の通り変更
use anyhow::Result;
use mcp_client::client::{ClientCapabilities, ClientInfo, McpClient, McpClientTrait};
use mcp_client::transport::{SseTransport, Transport};
use mcp_client::McpService;
use std::collections::HashMap;
use std::time::Duration;
use tracing_subscriber::EnvFilter;
#[tokio::main]
async fn main() -> Result<()> {
// Initialize logging
tracing_subscriber::fmt()
.with_env_filter(
EnvFilter::from_default_env()
.add_directive("mcp_client=debug".parse().unwrap())
.add_directive("eventsource_client=info".parse().unwrap()),
)
.init();
// Create the base transport
let transport = SseTransport::new("http://localhost:8000/sse", HashMap::new());
// Start transport
let handle = transport.start().await?;
// Create the service with timeout middleware
let service = McpService::with_timeout(handle, Duration::from_secs(3));
// Create client
let mut client = McpClient::new(service);
println!("Client created\n");
// Initialize
let server_info = client
.initialize(
ClientInfo {
name: "test-client".into(),
version: "1.0.0".into(),
},
ClientCapabilities::default(),
)
.await?;
println!("Connected to server: {server_info:?}\n");
// Sleep for 100ms to allow the server to start - surprisingly this is required!
tokio::time::sleep(Duration::from_millis(500)).await;
// List tools
let tools = client.list_tools(None).await?;
println!("Available tools: {tools:?}\n");
// Call tool
let tool_result = client
.call_tool(
"increment",
serde_json::json!({ "message": "Client with SSE transport - calling a tool" }),
)
.await?;
println!("'increment': Tool result: {tool_result:?}\n");
let tool_result = client
.call_tool(
"decrement",
serde_json::json!({ "message": "Client with SSE transport - calling a tool" }),
)
.await?;
println!("'decrement': Tool result: {tool_result:?}\n");
let tool_result = client
.call_tool(
"get_value",
serde_json::json!({ "message": "Client with SSE transport - calling a tool" }),
)
.await?;
println!("'get_value': Tool result: {tool_result:?}\n");
// List resources
// let resources = client.list_resources(None).await?;
// println!("Resources: {resources:?}\n");
// Read resource
// let resource = client.read_resource("echo://fixedresource").await?;
// println!("Resource: {resource:?}\n");
Ok(())
}

SSE clientコードの実行
cargo run --example sse
出力結果
2025-03-23T03:26:42.802688Z DEBUG mcp_client::transport::sse: Discovered SSE POST endpoint: http://localhost:8000/sse?sessionId=b9f03919f625f918848df10d336af205
Client created
Connected to server: InitializeResult { protocol_version: "2024-11-05", capabilities: ServerCapabilities { prompts: Some(PromptsCapability { list_changed: Some(false) }), resources: Some(ResourcesCapability { subscribe: Some(false), list_changed: Some(false) }), tools: Some(ToolsCapability { list_changed: Some(false) }) }, server_info: Implementation { name: "counter", version: "1.0.7" }, instructions: Some("This server provides a counter tool that can increment and decrement values. The counter starts at 0 and can be modified using the 'increment' and 'decrement' tools. Use 'get_value' to check the current count.") }
Available tools: ListToolsResult { tools: [Tool { name: "increment", description: "Increment the counter by 1", input_schema: Object {"properties": Object {}, "required": Array [], "type": String("object")} }, Tool { name: "decrement", description: "Decrement the counter by 1", input_schema: Object {"properties": Object {}, "required": Array [], "type": String("object")} }, Tool { name: "get_value", description: "Get the current counter value", input_schema: Object {"properties": Object {}, "required": Array [], "type": String("object")} }], next_cursor: None }
'increment': Tool result: CallToolResult { content: [Text(TextContent { text: "1", annotations: None })], is_error: None }
'decrement': Tool result: CallToolResult { content: [Text(TextContent { text: "0", annotations: None })], is_error: None }
'get_value': Tool result: CallToolResult { content: [Text(TextContent { text: "0", annotations: None })], is_error: None }
作成者以外のコメントは許可されていません