首页
/ 使用 rmcp 官方 SDK 构建 Rust MCP Server:Awesome Copilot 仓库实践指南

使用 rmcp 官方 SDK 构建 Rust MCP Server:Awesome Copilot 仓库实践指南

2026-09-09 20:34:31作者:霍妲思

本文基于 awesome-copilot 仓库中的 rust-mcp-server.instructions.md 开发规范,结合仓库内置的 rust-mcp-server-generator 技能rust-mcp-expert Agentrust-mcp-development 插件,系统讲解如何用官方 rmcp SDK 以 async/await 模式构建生产可用的 Model Context Protocol(MCP)服务器。读完本文,你将掌握从依赖配置、服务端骨架、宏化 Tool/Prompt/Resource 开发,到多种传输协议、错误处理、测试、性能优化与跨平台部署的完整链路,能够独立生成并交付一个类型安全的 Rust MCP Server 项目。

一、环境准备与依赖配置

在 Rust 生态中构建 MCP Server,核心依赖是官方 SDK rmcp(Rust Model Context Protocol 实现)。rust-mcp-server.instructions.md 给出了最小依赖集,你可以在 Cargo.toml 中按需组合。

1.1 基础依赖

[dependencies]
rmcp = { version = "0.8.1", features = ["server"] }
tokio = { version = "1", features = ["full"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
anyhow = "1.0"
tracing = "0.1"
tracing-subscriber = "0.3"

各依赖在工程中的职责:

  • rmcp(启用 server feature):提供 ServerServerHandlerServerCapabilitiesToolRouter 等核心服务端构件,以及 ErrorData、各类请求/响应模型;
  • tokiofull features):异步运行时,支撑 #[tokio::main]signal::ctrl_c()、异步 I/O 与锁;
  • serde / serde_json:Tool 参数的序列化/反序列化与 JSON 编解码;
  • anyhow:应用层错误的上抛与上下文增强(配合 .context());
  • tracing / tracing-subscriber:结构化日志与可观测性。

1.2 宏支持依赖

为了使用声明式宏简化 Tool 开发,还需引入宏与 JSON Schema 生成依赖:

[dependencies]
rmcp-macros = "0.8"
schemars = { version = "0.8", features = ["derive"] }
  • rmcp-macros 提供 #[tool]#[tool_router]#[tool_handler] 三个过程宏;
  • schemars 为 Tool 参数结构体自动生成 JSON Schema,供 MCP 客户端理解参数契约,是实现类型安全与自动参数校验的基础。

1.3 生产级模板:HTTP 传输的可选依赖与特性开关

仓库内置的 rust-mcp-server-generator 技能 在生成项目时给出了更完整的 Cargo.toml 模板,其通过 [features] 将 HTTP 相关依赖做成可选项,避免基础版本膨胀:

[dependencies]
rmcp = { version = "0.8.1", features = ["server"] }
rmcp-macros = "0.8"
tokio = { version = "1", features = ["full"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
anyhow = "1.0"
tracing = "0.1"
tracing-subscriber = "0.3"
schemars = { version = "0.8", features = ["derive"] }
async-trait = "0.1"

# Optional: for HTTP transports
axum = { version = "0.7", optional = true }
tower-http = { version = "0.5", features = ["cors"], optional = true }

[dev-dependencies]
tokio-test = "0.4"

[features]
default = []
http = ["dep:axum", "dep:tower-http"]

[[bin]]
name = "{project-name}"
path = "src/main.rs"

要点说明:

  • async-trait 用于为 ServerHandler 的异步 trait 方法提供支持;
  • axumtower-http(含 CORS)作为可选依赖,仅在启用 http feature 时编译,对应文档中的 SSE/Streamable HTTP 传输场景;
  • tokio-test 作为 dev-dependency,用于测试环境;
  • 显式声明 [[bin]],保证 cargo run 指向 src/main.rs

二、项目结构规划

文档建议按“能力模块”组织源码,这与 rust-mcp-server-generator 生成的骨架一致:

my-mcp-server/
├── Cargo.toml
├── src/
│   ├── main.rs           # Server entry point
│   ├── handler.rs        # ServerHandler implementation
│   ├── tools/
│   │   ├── mod.rs
│   │   ├── calculator.rs
│   │   └── greeter.rs
│   ├── prompts/
│   │   ├── mod.rs
│   │   └── code_review.rs
│   └── resources/
│       ├── mod.rs
│       └── data.rs
└── tests/
    └── integration_tests.rs

生成器模板在此基础上额外补充了 src/state.rs(共享状态模块)、.gitignoreREADME.md,并把 tests/integration_test.rs 用作端到端集成测试,形成一套可直接落地的工程化布局。README 中还会给出 Claude Desktop 等客户端的 JSON 接入配置,方便生成后立刻联调。

三、服务端实现

3.1 基本服务搭建(stdio 传输)

main.rs 中创建基于 stdio 传输的服务器,[rust-mcp-server.instructions.md](https://gitcode.com/GitHub_Trending/aw/awesome-copilot/blob/87ba8b1780d0e2655fc19fa3f8d4fc7879881744/instructions/rust-mcp-server.instructions.md?utm_source=gitcode_repo_files) 提供的入口代码如下:

use rmcp::{
    protocol::ServerCapabilities,
    server::{Server, ServerHandler},
    transport::StdioTransport,
};
use tokio::signal;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    tracing_subscriber::fmt::init();

    let handler = MyServerHandler::new();
    let transport = StdioTransport::new();

    let server = Server::builder()
        .with_handler(handler)
        .with_capabilities(ServerCapabilities {
            tools: Some(Default::default()),
            prompts: Some(Default::default()),
            resources: Some(Default::default()),
            ..Default::default()
        })
        .build(transport)?;

    server.run(signal::ctrl_c()).await?;

    Ok(())
}

这段代码的语义拆解:

  1. StdioTransport::new() 创建标准输入/输出传输,让服务可直接被本地 MCP 客户端以子进程方式拉起;
  2. ServerCapabilities 通过三个字段声明服务器对外暴露的能力维度——toolspromptsresourcesSome(Default::default()) 表示启用对应能力并使用默认配置;
  3. Server::builder().with_handler(handler).with_capabilities(...) 组装处理器与能力声明;
  4. server.run(signal::ctrl_c()) 以异步方式持续服务,收到 Ctrl+C 信号后优雅退出。

3.2 ServerHandler 实现

处理器是 MCP Server 的核心,必须实现 rmcp::server::ServerHandler trait。文档中的手写实现如下:

use rmcp::{
    model::*,
    protocol::*,
    server::{RequestContext, ServerHandler, RoleServer},
    ErrorData,
};

pub struct MyServerHandler {
    tool_router: ToolRouter,
}

impl MyServerHandler {
    pub fn new() -> Self {
        Self {
            tool_router: Self::create_tool_router(),
        }
    }

    fn create_tool_router() -> ToolRouter {
        // Initialize and return tool router
        ToolRouter::new()
    }
}

#[async_trait::async_trait]
impl ServerHandler for MyServerHandler {
    async fn list_tools(
        &self,
        _request: Option<PaginatedRequestParam>,
        _context: RequestContext<RoleServer>,
    ) -> Result<ListToolsResult, ErrorData> {
        let items = self.tool_router.list_all();
        Ok(ListToolsResult::with_all_items(items))
    }

    async fn call_tool(
        &self,
        request: CallToolRequestParam,
        context: RequestContext<RoleServer>,
    ) -> Result<CallToolResult, ErrorData> {
        let tcc = ToolCallContext::new(self, request, context);
        self.tool_router.call(tcc).await
    }
}

设计要点:

  • 处理器持有 ToolRouter 作为 Tool 注册与分发的中央路由,list_tools 时调用 list_all() 返回全部工具,call_tool 时构造 ToolCallContext 交由路由器执行;
  • 每个 trait 方法都接收 RequestContext<RoleServer>,其中包含会话上下文与进度通知通道(详见后文“进度通知”);
  • 返回值统一为 Result<_, ErrorData>,确保协议层错误语义一致。

从仓库的 rust-mcp-server-generator 技能 生成模板可见,更推荐的组合方式是:结构体持有 state: ServerStatetool_router: ToolRouter,用 #[tool_router] 宏把工具方法自动生成路由注册表,再用 #[tool_handler] 宏自动生成 ServerHandlerlist_tools/call_tool 胶水代码,从而省去上例中手写 trait 的样板:

#[tool_router]
impl McpHandler {
    #[tool(name = "example_tool", description = "An example tool",
           annotations(read_only_hint = true))]
    async fn example_tool(params: Parameters<tools::ExampleParams>) -> Result<String, String> {
        tools::example::execute(params).await
    }

    pub fn new() -> Self {
        Self {
            state: ServerState::new(),
            tool_router: Self::tool_router(),
        }
    }
}

#[tool_handler]
#[async_trait]
impl ServerHandler for McpHandler {
    // Prompt and resource handlers...
}

四、Tool 开发

4.1 用 #[tool] 宏声明式定义工具

文档推荐使用 rmcp::tool 宏把普通 async 函数变成 MCP Tool,参数结构体只需派生 DeserializeJsonSchema 即可获得自动化的参数 Schema 与反序列化:

use rmcp::tool;
use rmcp::model::Parameters;
use serde::{Deserialize, Serialize};
use schemars::JsonSchema;

#[derive(Debug, Deserialize, JsonSchema)]
pub struct CalculateParams {
    pub a: f64,
    pub b: f64,
    pub operation: String,
}

/// Performs mathematical calculations
#[tool(
    name = "calculate",
    description = "Performs basic arithmetic operations",
    annotations(read_only_hint = true)
)]
pub async fn calculate(params: Parameters<CalculateParams>) -> Result<f64, String> {
    let p = params.inner();
    match p.operation.as_str() {
        "add" => Ok(p.a + p.b),
        "subtract" => Ok(p.a - p.b),
        "multiply" => Ok(p.a * p.b),
        "divide" => {
            if p.b == 0.0 {
                Err("Division by zero".to_string())
            } else {
                Ok(p.a / p.b)
            }
        }
        _ => Err(format!("Unknown operation: {}", p.operation)),
    }
}

关键点:

  • Parameters<T> 是参数包装类型,params.inner() 取出反序列化后的 T
  • 函数上的 /// 文档注释会并入 Tool 描述,descriptionname 属性可覆盖或补充;
  • 返回 Result<T, String>,其中 Err 的字符串会成为对调用方可见的错误信息,如除零、未知操作符。

4.2 用 #[tool_router] 聚合多个工具

当工具数量变多时,文档展示了用 #[tool_router] + #[tool_handler] 组合在一个结构体上批量注册工具的方式:

use rmcp::{tool_router, tool_handler};

pub struct ToolsHandler {
    tool_router: ToolRouter,
}

#[tool_router]
impl ToolsHandler {
    #[tool]
    async fn greet(params: Parameters<GreetParams>) -> String {
        format!("Hello, {}!", params.inner().name)
    }

    #[tool(annotations(destructive_hint = true))]
    async fn reset_counter() -> String {
        "Counter reset".to_string()
    }

    pub fn new() -> Self {
        Self {
            tool_router: Self::tool_router(),
        }
    }
}

#[tool_handler]
impl ServerHandler for ToolsHandler {
    // Other handler methods...
}

值得注意的细节:

  • 宏会为结构体生成 tool_router() 关联函数,new() 中通过 Self::tool_router() 完成路由表初始化;
  • 无参数工具(如 reset_counter)可直接省略 params 参数;
  • 无副作用、只读的工具应标注 read_only_hint,而会修改状态的工具(如重置计数器)标注 destructive_hint,帮助 MCP 客户端(以及 Copilot 等 AI 客户端)判断调用风险。

rust-mcp-expert Agent 中,还演示了带共享状态的工具写法——工具方法可以直接接收 &ServerState 引用作为参数:

#[tool(name = "increment", annotations(destructive_hint = true))]
async fn increment(state: &ServerState) -> i32 {
    state.increment().await
}

4.3 Tool 注解(Annotations)的语义

Tool 注解是面向 MCP 客户端的行为提示,文档给出了两类典型组合:

#[tool(
    name = "delete_file",
    annotations(
        destructive_hint = true,
        read_only_hint = false,
        idempotent_hint = false
    )
)]
pub async fn delete_file(params: Parameters<DeleteParams>) -> Result<(), String> {
    // Delete file logic
}

#[tool(
    name = "search_data",
    annotations(
        read_only_hint = true,
        idempotent_hint = true,
        open_world_hint = true
    )
)]
pub async fn search_data(params: Parameters<SearchParams>) -> Vec<String> {
    // Search logic
}

三个 hint 的含义:

  • read_only_hint:标记只读操作(查询、搜索),客户端可安全地重复调用;
  • destructive_hint:标记破坏性操作(删除、重置),客户端会谨慎处理并可能要求确认;
  • idempotent_hint:标记幂等操作,重复执行结果一致,可安全重试;
  • open_world_hint:标记“开放世界”工具(如数据搜索),结果随外部数据变化,不可缓存。

4.4 返回富内容

工具不仅能返回纯字符串,还能返回结构化内容列表。文档展示了使用 ToolResponseContent 组合多条 TextContent

use rmcp::model::{ToolResponseContent, TextContent, ImageContent};

#[tool]
async fn analyze_code(params: Parameters<CodeParams>) -> ToolResponseContent {
    ToolResponseContent::from(vec![
        TextContent::text(format!("Analysis of {}:", params.inner().filename)),
        TextContent::text("No issues found."),
    ])
}

从导入可见,ImageContent 等类型同样可用于返回图片类内容,使工具能够向客户端交付多模态结果,而不仅是文本。

五、Prompt 实现

MCP 的 Prompt 能力让服务端向客户端提供可复用的提示词模板。文档实现 list_promptsget_prompt 两个处理器方法:

use rmcp::model::{Prompt, PromptArgument, PromptMessage, GetPromptResult};

async fn list_prompts(
    &self,
    _request: Option<PaginatedRequestParam>,
    _context: RequestContext<RoleServer>,
) -> Result<ListPromptsResult, ErrorData> {
    let prompts = vec![
        Prompt {
            name: "code-review".to_string(),
            description: Some("Review code for best practices".to_string()),
            arguments: Some(vec![
                PromptArgument {
                    name: "language".to_string(),
                    description: Some("Programming language".to_string()),
                    required: Some(true),
                },
            ]),
        },
    ];

    Ok(ListPromptsResult { prompts })
}

async fn get_prompt(
    &self,
    request: GetPromptRequestParam,
    _context: RequestContext<RoleServer>,
) -> Result<GetPromptResult, ErrorData> {
    match request.name.as_str() {
        "code-review" => {
            let language = request.arguments
                .as_ref()
                .and_then(|args| args.get("language"))
                .ok_or_else(|| ErrorData::invalid_params("language required"))?;

            Ok(GetPromptResult {
                description: Some("Code review prompt".to_string()),
                messages: vec![
                    PromptMessage::user(format!(
                        "Review this {} code for best practices and suggest improvements",
                        language
                    )),
                ],
            })
        }
        _ => Err(ErrorData::invalid_params("Unknown prompt")),
    }
}

实现要点:

  • PromptArgument 描述参数(名称、说明、是否必填),required: Some(true) 表示必填;
  • get_promptrequest.name 分发,参数缺失或未知 prompt 时统一返回 ErrorData::invalid_params
  • 使用 PromptMessage::user(...) 构造用户角色的消息内容。

rust-mcp-expert Agent 给出了更复杂的多参数示例(如 code-review 同时要求 languagecode 两个参数,并把用户代码拼入消息体),说明同一模式可轻松扩展为任意参数化模板。

六、Resource 实现

Resource 让服务器向客户端暴露结构化数据(文件、配置、数据集)。文档示例:

use rmcp::model::{Resource, ResourceContents, ReadResourceResult};

async fn list_resources(
    &self,
    _request: Option<PaginatedRequestParam>,
    _context: RequestContext<RoleServer>,
) -> Result<ListResourcesResult, ErrorData> {
    let resources = vec![
        Resource {
            uri: "file:///data/config.json".to_string(),
            name: "Configuration".to_string(),
            description: Some("Server configuration".to_string()),
            mime_type: Some("application/json".to_string()),
        },
    ];

    Ok(ListResourcesResult { resources })
}

async fn read_resource(
    &self,
    request: ReadResourceRequestParam,
    _context: RequestContext<RoleServer>,
) -> Result<ReadResourceResult, ErrorData> {
    match request.uri.as_str() {
        "file:///data/config.json" => {
            let content = r#"{"version": "1.0", "enabled": true}"#;
            Ok(ReadResourceResult {
                contents: vec![
                    ResourceContents::text(content.to_string())
                        .with_uri(request.uri)
                        .with_mime_type("application/json"),
                ],
            })
        }
        _ => Err(ErrorData::invalid_params("Unknown resource")),
    }
}

关键细节:

  • Resource 通过 uri(协议化资源标识符)、namedescriptionmime_type 描述资源元数据;
  • read_resource 依据 request.uri 分发,返回的 ResourceContents::text(...) 通过 .with_uri().with_mime_type() 补齐内容元数据;
  • rust-mcp-expert Agent 进一步演示了从共享状态加载设置并以 serde_json::to_string_pretty 序列化后返回的写法,ErrorData::internal_error 负责把内部错误映射为协议错误。

七、传输(Transport)选项

rmcp 支持多种传输方式,覆盖本地 CLI、远程 HTTP 与流式场景。

7.1 Stdio 传输(本地 CLI 集成)

use rmcp::transport::StdioTransport;

let transport = StdioTransport::new();
let server = Server::builder()
    .with_handler(handler)
    .build(transport)?;

这是最简单的模式,客户端以子进程方式启动服务并通过标准输入输出通信,适合 Claude Desktop、VS Code 等本地客户端集成。

7.2 SSE 传输(HTTP 事件流)

use rmcp::transport::SseServerTransport;
use std::net::SocketAddr;

let addr: SocketAddr = "127.0.0.1:8000".parse()?;
let transport = SseServerTransport::new(addr);

let server = Server::builder()
    .with_handler(handler)
    .build(transport)?;

server.run(signal::ctrl_c()).await?;

SSE 让服务以 HTTP 长连接方式暴露,客户端通过 Server-Sent Events 接收服务端推送。

7.3 Streamable HTTP 传输(Axum 集成)

use rmcp::transport::StreamableHttpTransport;
use axum::{Router, routing::post};

let transport = StreamableHttpTransport::new();
let app = Router::new()
    .route("/mcp", post(transport.handler()));

let listener = tokio::net::TcpListener::bind("127.0.0.1:3000").await?;
axum::serve(listener, app).await?;

Streamable HTTP 是最现代的 MCP 传输形态:服务通过 Axum 路由把 /mcp 端点交给 transport.handler() 处理,同时支持流式响应。注意:此模式需要启用 http feature(对应生成器模板中的 axum/tower-http 可选依赖),运行时用 cargo run --features http 启动。

7.4 自定义传输

use rmcp::transport::Transport;
use tokio::net::TcpListener;

// See examples/transport/ for TCP, Unix Socket, WebSocket implementations

Transport trait 是扩展点,TCP、Unix Socket、WebSocket 等传输均可按需实现;rust-mcp-expert Agent 的能力清单同样覆盖 Stdio、SSE、HTTP、WebSocket、TCP、Unix Socket 六类传输的咨询支持。

八、错误处理

8.1 协议层:ErrorData

ErrorData 是 MCP 协议层的错误载体,与 ServerHandler 方法的 Result<_, ErrorData> 返回类型严格对应:

use rmcp::ErrorData;

fn validate_params(value: &str) -> Result<(), ErrorData> {
    if value.is_empty() {
        return Err(ErrorData::invalid_params("Value cannot be empty"));
    }
    Ok(())
}

async fn call_tool(
    &self,
    request: CallToolRequestParam,
    context: RequestContext<RoleServer>,
) -> Result<CallToolResult, ErrorData> {
    validate_params(&request.name)?;

    // Tool execution...

    Ok(CallToolResult {
        content: vec![TextContent::text("Success")],
        is_error: Some(false),
    })
}
  • ErrorData::invalid_params(...) 表示参数类错误,其余还包括 internal_error(...) 等构造器(rust-mcp-expert Agent 中有明确使用示例);
  • 成功的 CallToolResult 显式携带 is_error: Some(false),向客户端表明执行成功。

8.2 应用层:anyhow

对服务器内部的非协议错误(文件读取、配置解析、网络请求),文档推荐用 anyhow 携带上下文逐层上抛:

use anyhow::{Context, Result};

async fn load_config() -> Result<Config> {
    let content = tokio::fs::read_to_string("config.json")
        .await
        .context("Failed to read config file")?;

    let config: Config = serde_json::from_str(&content)
        .context("Failed to parse config")?;

    Ok(config)
}

anyhow::Context 为底层错误追加“在哪一步失败”的说明,最终可在边界处用 ErrorData::internal_error(e.to_string()) 转换为协议错误(rust-mcp-expert Agent 的错误处理示例展示了这一完整链路)。

九、测试策略

9.1 单元测试(工具级)

文档为 calculate 工具编写了直接调用函数并断言返回值的测试:

#[cfg(test)]
mod tests {
    use super::*;

    #[tokio::test]
    async fn test_calculate_add() {
        let params = Parameters::new(CalculateParams {
            a: 5.0,
            b: 3.0,
            operation: "add".to_string(),
        });

        let result = calculate(params).await.unwrap();
        assert_eq!(result, 8.0);
    }

    #[tokio::test]
    async fn test_divide_by_zero() {
        let params = Parameters::new(CalculateParams {
            a: 5.0,
            b: 0.0,
            operation: "divide".to_string(),
        });

        let result = calculate(params).await;
        assert!(result.is_err());
    }
}

由于工具本身就是普通 async 函数,Parameters::new(...) 直接构造入参即可测试,无需启动完整服务器。生成器模板的工具模块(tools/example.rs)同样内嵌 #[cfg(test)] 单元测试,保持这一约定。

9.2 集成测试(处理器级)

集成测试直接实例化 ServerHandler 并调用其 trait 方法,验证完整服务器行为:

#[tokio::test]
async fn test_server_list_tools() {
    let handler = MyServerHandler::new();
    let context = RequestContext::default();

    let result = handler.list_tools(None, context).await.unwrap();

    assert!(!result.tools.is_empty());
    assert!(result.tools.iter().any(|t| t.name == "calculate"));
}

rust-mcp-server-generatortests/integration_test.rs 模板把这一模式扩展为四类断言:list_tools 非空且包含目标工具、call_tool 返回 Oklist_prompts 非空、list_resources 非空,覆盖了 Handler 的四大能力入口。由于 McpHandler 被放入 crate 根模块,集成测试可 use my_mcp_server::handler::McpHandler 直接引用。

十、进度通知

对于耗时操作,服务器应通过 RequestContext 发送进度通知,让客户端感知执行进度:

use rmcp::model::ProgressNotification;

#[tool]
async fn process_large_file(
    params: Parameters<ProcessParams>,
    context: RequestContext<RoleServer>,
) -> Result<String, String> {
    let total = 100;

    for i in 0..=total {
        // Do work...

        if i % 10 == 0 {
            context.notify_progress(ProgressNotification {
                progress: i,
                total: Some(total),
            }).await.ok();
        }
    }

    Ok("Processing complete".to_string())
}

要点:工具方法把 RequestContext<RoleServer> 作为额外参数即可获得通知能力;ProgressNotification 携带 progress(当前进度)与 total(总量,可选);每完成 10% 上报一次,避免通知风暴。文档强调发送失败用 .ok() 容忍(通知是尽力而为的)。

十一、OAuth 认证

面向远程部署时,可在服务器侧接入 OAuth 保护访问。文档给出的配置骨架:

use rmcp::oauth::{OAuthConfig, OAuthProvider};

let oauth_config = OAuthConfig {
    authorization_endpoint: "https://auth.example.com/authorize".to_string(),
    token_endpoint: "https://auth.example.com/token".to_string(),
    client_id: env::var("CLIENT_ID")?,
    client_secret: env::var("CLIENT_SECRET")?,
    scopes: vec!["read".to_string(), "write".to_string()],
};

let oauth_provider = OAuthProvider::new(oauth_config);
  • OAuthConfig 声明授权端点、令牌端点、客户端凭据与 scope;
  • client_id / client_secret 从环境变量读取,避免硬编码泄露;
  • 完整示例可参考官方 rust-sdk 示例中的 complex_auth_sse 实现(文档原文指向外部示例,此处仅作实现思路说明)。

十二、性能最佳实践

12.1 全程异步化

所有处理器与工具方法都应保持 async,阻塞 I/O 场景使用 tokio 的异步版本:

#[tool]
async fn fetch_data(params: Parameters<FetchParams>) -> Result<String, String> {
    let client = reqwest::Client::new();
    let response = client
        .get(&params.inner().url)
        .send()
        .await
        .map_err(|e| e.to_string())?;

    let text = response.text().await.map_err(|e| e.to_string())?;
    Ok(text)
}

网络请求通过 reqwest 异步执行,.await 挂起而不阻塞 tokio 工作线程,确保高并发下吞吐稳定。

12.2 共享状态:Arc + RwLock

跨工具共享的可变状态用 Arc 包裹 RwLock,实现多任务安全访问:

use std::sync::Arc;
use tokio::sync::RwLock;

pub struct ServerState {
    counter: Arc<RwLock<i32>>,
}

impl ServerState {
    pub fn new() -> Self {
        Self {
            counter: Arc::new(RwLock::new(0)),
        }
    }

    pub async fn increment(&self) -> i32 {
        let mut counter = self.counter.write().await;
        *counter += 1;
        *counter
    }
}

生成器模板的 state.rs 实现 还补充了 get() 只读方法与 #[derive(Clone)](配合 Arc 实现零拷贝克隆共享)。

12.3 锁与并发细节

rust-mcp-expert Agent 的性能建议值得沉淀为工程准则:

  • 按负载选锁:读多写少用 RwLock,写多读少用 Mutex,高并发哈希表可考虑 DashMap
  • 缩短持锁时间:不要在持锁状态下执行 async 操作,应先把数据 clone 出锁再处理——例如 let value = { self.data.read().await.clone() }; 后再做耗时处理;
  • 使用带缓冲的 channel:如 tokio::sync::mpsc::channel(100) 缓冲任务队列;
  • 批量并发处理:用 futures::future::join_all 对一批任务并发执行。

十三、日志与追踪

tracing 提供从结构化日志到分布式追踪的统一抽象,文档给出了初始化与使用示例:

use tracing::{info, warn, error, debug};
use tracing_subscriber;

fn init_logging() {
    tracing_subscriber::fmt()
        .with_max_level(tracing::Level::DEBUG)
        .with_target(false)
        .with_thread_ids(true)
        .init();
}

#[tool]
async fn my_tool(params: Parameters<MyParams>) -> String {
    debug!("Tool called with params: {:?}", params);
    info!("Processing request");

    // Tool logic...

    info!("Request completed");
    "Done".to_string()
}

配置项说明:

  • .with_max_level(DEBUG) 设置全局最大日志级别;
  • .with_target(false) 隐藏模块路径,日志更清爽;
  • .with_thread_ids(true) 输出线程 ID,便于排查并发问题;
  • 在工具内部用 debug!/info! 记录入参与执行阶段,运行时可通过 RUST_LOG=debug cargo run(生成器 README 中的方式)动态控制日志详略。

十四、部署与分发

14.1 发布二进制

cargo build --release --target x86_64-unknown-linux-gnu
cargo build --release --target x86_64-pc-windows-msvc
cargo build --release --target x86_64-apple-darwin

14.2 交叉编译

使用 cross 工具在单一构建机上产出多平台产物:

cargo install cross
cross build --release --target aarch64-unknown-linux-gnu

rust-mcp-expert Agent 补充了 ARM 目标(aarch64-unknown-linux-gnu)等典型场景,方便为树莓派、ARM 服务器交付。

14.3 Docker 部署

文档给出的 Dockerfile 采用两阶段构建,缩小最终镜像体积:

FROM rust:1.75 as builder
WORKDIR /app
COPY . .
RUN cargo build --release

FROM debian:bookworm-slim
RUN apt-get update && apt-get install -y ca-certificates
COPY --from=builder /app/target/release/my-mcp-server /usr/local/bin/
CMD ["my-mcp-server"]
  • 第一阶段用 rust:1.75 编译发布产物;
  • 第二阶段基于 debian:bookworm-slim 仅复制二进制与 ca-certificates(保证 TLS/HTTPS 调用可用);
  • rust-mcp-expert Agent 的版本进一步优化了缓存(先拷贝 Cargo.toml Cargo.lock 再拷 src)并在 RUN 后清理 apt 缓存,值得采纳。

14.4 客户端接入配置

编译完成后,在 MCP 客户端(如 Claude Desktop)的配置文件中以 JSON 注册 stdio 服务器:

{
  "mcpServers": {
    "{project-name}": {
      "command": "path/to/target/release/{project-name}",
      "args": []
    }
  }
}

command 指向发布二进制绝对路径,args 为空数组(无额外参数)。

十五、在 Awesome Copilot 仓库中的配套资源

本指南对应的规范文档是 rust-mcp-server.instructions.md,它声明 applyTo: '**/*.rs',即该规范面向仓库内所有 Rust 文件生效。围绕同一主题,仓库还提供了一整套可直接使用的配套资源:

  • rust-mcp-server-generator 技能:一次对话即可生成完整工程——它会询问项目名、服务描述、传输类型(stdio/sse/http/all)、工具清单以及是否需要 prompts/resources,然后按模板产出 Cargo.tomlmain.rshandler.rsstate.rstools/prompts/resources/tests/README.md,生成后执行 cargo build && cargo test && cargo run 即可运行;
  • rust-mcp-expert Agent:专门的 MCP Server 开发专家,覆盖 rmcp v0.8+ SDK、宏体系、tokio 异步、serde/JsonSchema 类型安全、六类传输、错误处理、测试、性能优化与部署咨询;
  • rust-mcp-development 插件:将上述技能与 Agent 打包为插件,可通过 copilot plugin install rust-mcp-development@awesome-copilot 安装,其 plugin.json 声明了 /rust-mcp-development:rust-mcp-server-generator 斜杠命令与 rust-mcp-expert Agent 的关联关系。

三者与规范文档共同构成“规范 + 生成器 + 专家 + 一键安装”的完整开发闭环:规范文档约束写法,生成器输出骨架,专家 Agent 答疑解惑,插件实现分发集成。开发者可以直接以本指南为纲,配合上述资源快速落地自己的 Rust MCP Server。

热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
docsdocs
暂无描述
Markdown
900
5.83 K
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.14 K
2.76 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
860
1.35 K
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
927
1.85 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.94 K
1.02 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
533
603
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.37 K
1.46 K
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
548
396
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.04 K
527