使用 Rust 构建 MCP Server 供 Claude Code 使用
本文档详细介绍如何使用 Rust 语言构建一个 MCP (Model Context Protocol) Server,并将其配置到 Claude Code 中使用。
目录
- [什么是 MCP](#什么是 MCP "#%E4%BB%80%E4%B9%88%E6%98%AF-mcp")
- 项目结构
- 核心代码解析
- 构建和运行
- [配置到 Claude Code](#配置到 Claude Code "#%E9%85%8D%E7%BD%AE%E5%88%B0-claude-code")
- 常见问题
- 参考资源
什么是 MCP
MCP (Model Context Protocol) 是一个开放协议,允许 AI 助手(如 Claude)与外部工具和数据源进行通信。通过 MCP Server,你可以:
- 为 Claude 提供自定义工具(tools)
- 让 Claude 访问外部系统(如数据库、API、监控系统等)
- 扩展 Claude 的能力,使其能够执行特定任务
MCP Server 通信方式:
- stdio: 通过标准输入/输出进行通信(本文重点)
- SSE: 通过服务器发送事件进行通信
项目结构
bash
prometheus-mcp-server/
├── Cargo.toml # Rust 项目配置文件
└── src/
├── main.rs # 程序入口,负责启动 MCP Server
└── searcher/
├── mod.rs # 模块声明
└── basic_component.rs # 核心 MCP 实现
Cargo.toml 依赖说明
toml
[package]
name = "prometheus-mcp-server"
version = "0.1.0"
edition = "2021"
[dependencies]
# 异步运行时
tokio = { version = "1.48", features = ["full"] }
# HTTP 客户端
reqwest = { version = "0.12", features = ["json"] }
# 序列化/反序列化
serde = { version = "1.0", features = ["derive"] }
# JSON 支持
serde_json = "1.0"
# 日志框架
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter", "std", "fmt"] }
# MCP SDK (核心依赖)
rmcp = { version = "0.12.0", features = ["server", "macros", "transport-io"] }
# 时间处理
chrono = "0.4"
# 错误处理
anyhow = "1.0"
# JSON Schema 生成
schemars = "1.2"
关键依赖是 rmcp,这是 Rust 语言的 MCP SDK。
核心代码解析
1. src/main.rs - 程序��口(完整代码)
rust
use anyhow::{Context, Result};
use rmcp::ServiceExt;
use tokio::io::{stdin, stdout};
use tracing::info;
use tracing_subscriber::fmt::{format::Writer, time::FormatTime};
use crate::searcher::basic_component::BasicComponent;
pub mod searcher;
#[tokio::main]
async fn main() -> Result<()> {
tracing_subscriber::fmt()
.with_timer(LocalTimer)
.with_thread_ids(true)
.with_thread_names(true)
.with_line_number(true)
.init();
info!("start prometheus mcp server...");
BasicComponent::new()
.serve((stdin(), stdout()))
.await
.context("Failed to serve MCP server")?
.waiting()
.await
.context("Error while waiting for server shutdown")?;
Ok(())
}
struct LocalTimer;
const fn east_utf8() -> Option<chrono::FixedOffset> {
chrono::FixedOffset::east_opt(8 * 3600)
}
impl FormatTime for LocalTimer {
fn format_time(&self, w: &mut Writer<'_>) -> std::fmt::Result {
let now = chrono::Utc::now().with_timezone(&east_utf8().unwrap());
write!(w, "{}", now.format("%FT%T%.3f"))
}
}
关键点:
- 使用
tokio异步运行时 - 通过
stdin()和stdout()进行 stdio 通信 - 调用
serve()方法启动 MCP 服务 - 自定义
LocalTimer实现本地时区(东八区)的时间戳格式化
2. src/searcher/mod.rs - 模块声明(完整代码)
rust
pub mod basic_component;
3. src/searcher/basic_component.rs - MCP Server 实现(完整代码)
rust
use rmcp::{
ErrorData, RoleServer, ServerHandler,
handler::server::{tool::ToolRouter, wrapper::Parameters},
model::{Implementation, ProtocolVersion, ServerCapabilities, ServerInfo, ToolsCapability},
schemars::JsonSchema,
service::{NotificationContext, RequestContext},
tool, tool_handler, tool_router,
};
use serde::{Deserialize, Serialize};
use tracing::info;
///
/// 放置基础组件的指标访问
///
#[derive(Serialize, Deserialize, JsonSchema)]
pub struct MCPNodeMemoryRequest {
#[schemars(description = "开始时间戳,单位毫秒")]
start: u64,
#[schemars(description = "结束时间戳,单位毫秒")]
end: u64,
}
impl MCPNodeMemoryRequest {
pub fn start(&self) -> u64 {
self.start
}
pub fn end(&self) -> u64 {
self.end
}
}
pub struct BasicComponent {
tool_router: ToolRouter<BasicComponent>,
}
#[tool_router(router = tool_router)]
impl BasicComponent {
pub fn new() -> Self {
Self {
tool_router: Self::tool_router(),
}
}
#[tool(description = "获取start和end之间的一个时间点的毫秒字符串")]
pub async fn middle_time(
&self,
Parameters(request): Parameters<MCPNodeMemoryRequest>,
) -> String {
info!(
"MCPServer触发请求,start is {} end is:{}!",
request.start(),
request.end()
);
chrono::Local::now().to_string()
}
}
#[tool_handler(router = self.tool_router)]
impl ServerHandler for BasicComponent {
fn get_info(&self) -> ServerInfo {
ServerInfo {
protocol_version: ProtocolVersion::V_2024_11_05,
capabilities: ServerCapabilities {
tools: Some(ToolsCapability {
list_changed: Some(false),
}),
..Default::default()
},
instructions: Some(
"Prometheus MCP Sserver providing metrics search for business!".into(),
),
server_info: Implementation {
name: "prometheus-mcp-server".into(),
version: "0.1.0".into(),
..Default::default()
},
}
}
async fn ping(&self, _ctx: RequestContext<RoleServer>) -> Result<(), ErrorData> {
info!("Received ping request");
Ok(())
}
async fn on_initialized(&self, _ctx: NotificationContext<RoleServer>) {
info!("Client initialized successfully");
}
}
关键宏:
#[tool_router]- 标记 impl 块,自动生成工具路由#[tool(description = "...")]- 标记函数为可调用工具,并添加描述#[tool_handler(router = self.tool_router)]- 标记 ServerHandler 实现Parameters(request)- 自动解析 JSON 参数为结构体
代码结构说明:
MCPNodeMemoryRequest- 请求参数结构体,使用JsonSchemaderive 自动生成 JSON SchemaMCPNodeMemoryRequest的 impl 块提供 getter 方法start()和end()BasicComponentstruct 包含tool_router字段用于工具路由#[tool_router]impl 块中定义 MCP 工具(如middle_time)#[tool_handler]impl 块实现ServerHandlertrait,提供服务器信息和生命周期回调
构建和运行
1. 构建项目
在项目根目录执行:
bash
# 开发版本构建
cargo build
# 发布版本构建(优化性能)
cargo build --release
# 仅构建 prometheus-mcp-server
cargo build -p prometheus-mcp-server --release
2. 运行 Server
bash
# 开发版本
因为是stdio类型,所以就等着claude code直接调用就行了
注意:stdio 类型的 MCP Server 启动后会等待通过 stdin 接收 JSON-RPC 消息,不会有其他输出。
3. 测试 Server
可以通过以下方式测试:
bash
# 发送初始化消息
echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}}}' | cargo run -p prometheus-mcp-server
配置到 Claude Code
1. 找到 Claude Code 配置文件
Claude Code 的 MCP 配置文件位置:
- Linux :
~/.claude.json#对应claude code版本为2.1.7
2. 编辑配置文件
在配置文件中添加 MCP Server 配置:
json
#注意添加的位置,下面是全局的,也可以对项目级别
{
"mcpServers": {
"prometheus-metrics": {
"command": "/path/to/prometheus-mcp-server",
"args": [],
"env": {
"RUST_LOG": "info",
"PROMETHEUS_URL": "http://your-prometheus:9090"
}
}
},
#这个是Project级别
"projects": {
"/media/liuxu/data/code/github/binlog-cdc": {
"allowedTools": [],
"mcpContextUris": [],
"mcpServers": {
"prometheus-mcp-server": {
"type": "stdio",
"command": "/media/user/data/code/bitbucket/cpaas-cicd-event-rust/target/release/prometheus-mcp-server",
"args": [],
"env": {}
}
}
......
}
}
配置说明:
| 字段 | 说明 | 示例 |
|---|---|---|
command |
MCP Server 可执行文件的绝对路径 | /home/user/projects/cpaas-cicd-event-rust/target/release/prometheus-mcp-server |
args |
命令行参数数组 | ["--port", "9090"] |
env |
环境变量 | {"RUST_LOG": "debug"} |
3. 获取可执行文件路径
bash
# 获取项目根目录的绝对路径
pwd
# 构建后,可执行文件位于
# /path/to/project/target/release/prometheus-mcp-server
4. 完整配置示例
假设项目位于 /home/user/projects/cpaas-cicd-event-rust/:
json
{
"mcpServers": {
"prometheus-metrics": {
"command": "/home/user/projects/cpaas-cicd-event-rust/target/release/prometheus-mcp-server",
"args": [],
"env": {
"RUST_LOG": "info"
}
}
}
}
5. 重启 Claude Code
配置完成后,重启 Claude Code 使配置生效。
6. 验证配置
在 Claude Code 中,你的 MCP Server 提供的工具应该可以使用了。可以尝试��
ini
使用 middle_time 工具,参数 start=1704067200000, end=1704153600000
常见问题
Q: MCP Server 启动后没有输出?
A: stdio 类型的 MCP Server 通过标准输入/输出与 Claude Code 通信,不应该有其他日志输出。建议使用 RUST_LOG=error 减少日志。
Q: Claude Code 无法连接到 MCP Server?
A: 检查以下几点:
- 可执行文件路径是否正确
- 文件是否有执行权限 (
chmod +x prometheus-mcp-server) - 查看 Claude Code 日志是否有错误信息
Q: 如何调试 MCP Server?
A: 可以单独测试 Server:
bash
echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{...}}' | ./prometheus-mcp-server
Q: 如何添加更多工具?
A: 在 impl 块中添加更多 #[tool] 标记的函数:
rust
#[tool(description = "第二个工具")]
pub async fn second_tool(&self, Parameters(req): Parameters<MCPNodeMemoryRequest>) -> String {
// 实现逻辑
}
参考资源
项目文件位置
- 本文档 :
prometheus-mcp-server/如何构建MCP服务器.md - 源码目录 :
prometheus-mcp-server/src/ - 配置文件 :
prometheus-mcp-server/Cargo.toml