主题
Rust SDK
Model Context Protocol (MCP) 的 Rust SDK 提供了高性能、内存安全的 MCP 服务器和客户端实现。
安装
在 Cargo.toml
中添加依赖:
toml
[dependencies]
mcp-rust-sdk = "1.0.0"
tokio = { version = "1.0", features = ["full"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
快速开始
创建 MCP 服务器
rust
use mcp_rust_sdk::server::{McpServer, ServerBuilder};
use mcp_rust_sdk::tool::{Tool, ToolCall, ToolResult, ToolSchema};
use mcp_rust_sdk::schema::JsonSchema;
use async_trait::async_trait;
use serde_json::{json, Value};
use std::collections::HashMap;
#[derive(Clone)]
struct EchoTool;
#[async_trait]
impl Tool for EchoTool {
fn name(&self) -> &str {
"echo"
}
fn description(&self) -> &str {
"回显输入的消息"
}
fn input_schema(&self) -> JsonSchema {
JsonSchema::object()
.property("message", JsonSchema::string().description("要回显的消息"))
.required(&["message"])
}
async fn call(&self, call: ToolCall) -> Result<ToolResult, Box<dyn std::error::Error + Send + Sync>> {
let message = call.arguments
.get("message")
.and_then(|v| v.as_str())
.ok_or("缺少 message 参数")?;
let result = json!({
"echo": message
});
Ok(ToolResult::success(result))
}
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// 创建服务器
let server = ServerBuilder::new()
.name("my-rust-server")
.version("1.0.0")
.description("Rust MCP 服务器示例")
.build();
// 注册工具
server.register_tool(Box::new(EchoTool)).await;
// 启动服务器
server.serve().await?;
Ok(())
}
创建 MCP 客户端
rust
use mcp_rust_sdk::client::{McpClient, ClientBuilder};
use mcp_rust_sdk::transport::{StdioTransport, Transport};
use serde_json::json;
use std::time::Duration;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// 创建传输层
let transport = StdioTransport::new();
// 创建客户端
let client = ClientBuilder::new()
.transport(Box::new(transport))
.connect_timeout(Duration::from_secs(10))
.request_timeout(Duration::from_secs(30))
.build();
// 连接到服务器
client.connect().await?;
// 列出可用工具
let tools = client.list_tools().await?;
println!("可用工具: {:?}", tools);
// 调用工具
let args = json!({
"message": "Hello from Rust!"
});
let result = client.call_tool("echo", args).await?;
println!("工具调用结果: {:?}", result);
// 关闭连接
client.close().await?;
Ok(())
}
核心功能
服务器功能
工具注册
rust
use mcp_rust_sdk::tool::{Tool, ToolCall, ToolResult};
use async_trait::async_trait;
// 简单计算器工具
#[derive(Clone)]
struct CalculatorTool;
#[async_trait]
impl Tool for CalculatorTool {
fn name(&self) -> &str {
"calculator"
}
fn description(&self) -> &str {
"执行基本数学运算"
}
fn input_schema(&self) -> JsonSchema {
JsonSchema::object()
.property("operation", JsonSchema::string()
.enum_values(&["add", "subtract", "multiply", "divide"]))
.property("a", JsonSchema::number().description("第一个数字"))
.property("b", JsonSchema::number().description("第二个数字"))
.required(&["operation", "a", "b"])
}
async fn call(&self, call: ToolCall) -> Result<ToolResult, Box<dyn std::error::Error + Send + Sync>> {
let operation = call.arguments["operation"].as_str().unwrap();
let a = call.arguments["a"].as_f64().unwrap();
let b = call.arguments["b"].as_f64().unwrap();
let result = match operation {
"add" => a + b,
"subtract" => a - b,
"multiply" => a * b,
"divide" => {
if b == 0.0 {
return Ok(ToolResult::error("除数不能为零"));
}
a / b
}
_ => return Ok(ToolResult::error("不支持的运算")),
};
Ok(ToolResult::success(json!({ "result": result })))
}
}
// 注册工具
server.register_tool(Box::new(CalculatorTool)).await;
资源管理
rust
use mcp_rust_sdk::resource::{Resource, ResourceProvider, ResourceUri};
use async_trait::async_trait;
use tokio::fs;
#[derive(Clone)]
struct FileResourceProvider {
base_path: String,
}
#[async_trait]
impl ResourceProvider for FileResourceProvider {
async fn get_resource(&self, uri: &ResourceUri) -> Result<Resource, Box<dyn std::error::Error + Send + Sync>> {
let file_path = format!("{}/{}", self.base_path, uri.path());
let content = fs::read_to_string(&file_path).await?;
Ok(Resource::new()
.uri(uri.clone())
.mime_type("text/plain")
.content(content))
}
async fn list_resources(&self) -> Result<Vec<ResourceUri>, Box<dyn std::error::Error + Send + Sync>> {
let mut resources = Vec::new();
let mut entries = fs::read_dir(&self.base_path).await?;
while let Some(entry) = entries.next_entry().await? {
if entry.file_type().await?.is_file() {
let uri = ResourceUri::from_str(&format!("file://{}", entry.path().display()))?;
resources.push(uri);
}
}
Ok(resources)
}
}
// 注册资源提供者
let provider = FileResourceProvider {
base_path: "/path/to/files".to_string(),
};
server.register_resource_provider(Box::new(provider)).await;
提示模板
rust
use mcp_rust_sdk::prompt::{Prompt, PromptProvider, PromptTemplate};
use async_trait::async_trait;
use std::collections::HashMap;
#[derive(Clone)]
struct CodeReviewPromptProvider;
#[async_trait]
impl PromptProvider for CodeReviewPromptProvider {
async fn get_prompt(&self, name: &str, arguments: HashMap<String, Value>) -> Result<Prompt, Box<dyn std::error::Error + Send + Sync>> {
match name {
"code-review" => {
let code = arguments.get("code")
.and_then(|v| v.as_str())
.ok_or("缺少 code 参数")?;
let language = arguments.get("language")
.and_then(|v| v.as_str())
.unwrap_or("unknown");
let content = format!(
"请审查以下 {} 代码并提供改进建议:\n\n```{}\n{}\n```",
language, language, code
);
Ok(Prompt::new()
.name(name)
.description("代码审查提示")
.content(content))
}
_ => Err(format!("未知提示: {}", name).into()),
}
}
async fn list_prompts(&self) -> Result<Vec<String>, Box<dyn std::error::Error + Send + Sync>> {
Ok(vec!["code-review".to_string()])
}
}
// 注册提示提供者
server.register_prompt_provider(Box::new(CodeReviewPromptProvider)).await;
客户端功能
连接管理
rust
use mcp_rust_sdk::client::{McpClient, ConnectionListener};
use async_trait::async_trait;
#[derive(Clone)]
struct MyConnectionListener;
#[async_trait]
impl ConnectionListener for MyConnectionListener {
async fn on_connected(&self) {
println!("已连接到服务器");
}
async fn on_disconnected(&self) {
println!("与服务器断开连接");
}
async fn on_error(&self, error: Box<dyn std::error::Error + Send + Sync>) {
eprintln!("连接错误: {}", error);
}
}
// 创建带自动重连的客户端
let client = ClientBuilder::new()
.transport(transport)
.auto_reconnect(true)
.max_reconnect_attempts(5)
.reconnect_delay(Duration::from_secs(2))
.connection_listener(Box::new(MyConnectionListener))
.build();
并发操作
rust
use tokio::try_join;
// 并发调用多个工具
let (result1, result2, result3) = try_join!(
client.call_tool("tool1", json!({"arg": "value1"})),
client.call_tool("tool2", json!({"arg": "value2"})),
client.call_tool("tool3", json!({"arg": "value3"}))
)?;
println!("结果1: {:?}", result1);
println!("结果2: {:?}", result2);
println!("结果3: {:?}", result3);
传输协议
Stdio 传输
rust
use mcp_rust_sdk::transport::StdioTransport;
let transport = StdioTransport::builder()
.command("python")
.args(&["server.py"])
.working_directory("/path/to/server")
.environment("ENV_VAR", "value")
.build();
WebSocket 传输
rust
use mcp_rust_sdk::transport::WebSocketTransport;
use std::collections::HashMap;
let mut headers = HashMap::new();
headers.insert("Authorization".to_string(), "Bearer token".to_string());
let transport = WebSocketTransport::builder()
.uri("ws://localhost:8080/mcp")
.headers(headers)
.connect_timeout(Duration::from_secs(10))
.build();
HTTP SSE 传输
rust
use mcp_rust_sdk::transport::SseTransport;
let transport = SseTransport::builder()
.uri("http://localhost:8080/mcp")
.headers(headers)
.read_timeout(Duration::from_secs(30))
.build();
高级特性
中间件支持
rust
use mcp_rust_sdk::middleware::{Middleware, MiddlewareChain};
use async_trait::async_trait;
#[derive(Clone)]
struct LoggingMiddleware;
#[async_trait]
impl Middleware for LoggingMiddleware {
async fn handle(&self, request: Request, chain: MiddlewareChain) -> Result<Response, Box<dyn std::error::Error + Send + Sync>> {
println!("处理请求: {}", request.method());
let start_time = std::time::Instant::now();
let result = chain.next(request).await;
let duration = start_time.elapsed();
println!("请求完成,耗时: {:?}", duration);
result
}
}
// 添加中间件
server.add_middleware(Box::new(LoggingMiddleware)).await;
事件系统
rust
use mcp_rust_sdk::events::{EventListener, ServerEvent, ToolCallEvent};
use async_trait::async_trait;
#[derive(Clone)]
struct MyEventListener;
#[async_trait]
impl EventListener for MyEventListener {
async fn on_event(&self, event: ServerEvent) {
match event {
ServerEvent::ToolCalled(tool_event) => {
println!("工具被调用: {}", tool_event.tool_name());
}
ServerEvent::Error(error_event) => {
eprintln!("服务器错误: {}", error_event.error());
}
_ => {}
}
}
}
// 添加事件监听器
server.add_event_listener(Box::new(MyEventListener)).await;
配置管理
rust
use mcp_rust_sdk::config::{McpConfig, ServerConfig, LoggingConfig};
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize)]
struct AppConfig {
mcp: McpConfig,
}
// 从配置文件加载
let config_str = tokio::fs::read_to_string("mcp-config.toml").await?;
let app_config: AppConfig = toml::from_str(&config_str)?;
let server = ServerBuilder::new()
.config(app_config.mcp)
.build();
// 程序化配置
let config = McpConfig::builder()
.server(ServerConfig::builder()
.name("my-server")
.version("1.0.0")
.max_connections(100)
.request_timeout(Duration::from_secs(30))
.build())
.logging(LoggingConfig::builder()
.level("info")
.file("/var/log/mcp-server.log")
.build())
.build();
测试
单元测试
rust
#[cfg(test)]
mod tests {
use super::*;
use tokio_test;
#[tokio::test]
async fn test_echo_tool() {
let tool = EchoTool;
let call = ToolCall::new()
.name("echo")
.arguments(json!({"message": "test"}));
let result = tool.call(call).await.unwrap();
assert!(result.is_success());
assert_eq!(result.content()["echo"], "test");
}
#[tokio::test]
async fn test_echo_tool_missing_argument() {
let tool = EchoTool;
let call = ToolCall::new()
.name("echo")
.arguments(json!({}));
let result = tool.call(call).await;
assert!(result.is_err());
}
}
集成测试
rust
#[cfg(test)]
mod integration_tests {
use super::*;
use tokio_test;
#[tokio::test]
async fn test_server_client_integration() {
// 启动测试服务器
let server = ServerBuilder::new()
.name("test-server")
.build();
server.register_tool(Box::new(EchoTool)).await;
let server_handle = tokio::spawn(async move {
server.serve().await
});
// 等待服务器启动
tokio::time::sleep(Duration::from_millis(100)).await;
// 创建客户端并测试
let transport = StdioTransport::new();
let client = ClientBuilder::new()
.transport(Box::new(transport))
.build();
client.connect().await.unwrap();
let result = client.call_tool("echo", json!({"message": "test"})).await.unwrap();
assert_eq!(result["echo"], "test");
client.close().await.unwrap();
server_handle.abort();
}
}
部署
Docker 部署
dockerfile
FROM rust:1.70 as builder
WORKDIR /app
COPY Cargo.toml Cargo.lock ./
COPY src ./src
RUN cargo build --release
FROM debian:bookworm-slim
RUN apt-get update && apt-get install -y \
ca-certificates \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY --from=builder /app/target/release/mcp-server .
CMD ["./mcp-server"]
系统服务
ini
[Unit]
Description=MCP Rust Server
After=network.target
[Service]
Type=simple
User=mcp
ExecStart=/usr/local/bin/mcp-server
Restart=always
RestartSec=5
Environment=RUST_LOG=info
[Install]
WantedBy=multi-user.target
性能优化
rust
// 使用 tokio 运行时优化
#[tokio::main(flavor = "multi_thread", worker_threads = 4)]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// 服务器配置
let server = ServerBuilder::new()
.name("high-performance-server")
.max_connections(1000)
.worker_threads(8)
.enable_tcp_nodelay(true)
.buffer_size(8192)
.build();
server.serve().await?;
Ok(())
}
// 内存池优化
use object_pool::Pool;
lazy_static! {
static ref BUFFER_POOL: Pool<Vec<u8>> = Pool::new(100, || Vec::with_capacity(4096));
}
// 使用内存池
let mut buffer = BUFFER_POOL.try_pull().unwrap_or_else(|| Vec::with_capacity(4096));
// 使用 buffer...
buffer.clear();
BUFFER_POOL.attach(buffer);