Skip to content

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);

相关资源

社区支持

🚀 探索模型上下文协议的无限可能 | 连接 AI 与世界的桥梁 | 让智能更智能