使用Rust构建MCP Server Stdio类型

使用 Rust 构建 MCP Server 供 Claude Code 使用

本文档详细介绍如何使用 Rust 语言构建一个 MCP (Model Context Protocol) Server,并将其配置到 Claude Code 中使用。

目录

  1. [什么是 MCP](#什么是 MCP "#%E4%BB%80%E4%B9%88%E6%98%AF-mcp")
  2. 项目结构
  3. 核心代码解析
  4. 构建和运行
  5. [配置到 Claude Code](#配置到 Claude Code "#%E9%85%8D%E7%BD%AE%E5%88%B0-claude-code")
  6. 常见问题
  7. 参考资源

什么是 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 参数为结构体

代码结构说明

  1. MCPNodeMemoryRequest - 请求参数结构体,使用 JsonSchema derive 自动生成 JSON Schema
  2. MCPNodeMemoryRequest 的 impl 块提供 getter 方法 start()end()
  3. BasicComponent struct 包含 tool_router 字段用于工具路由
  4. #[tool_router] impl 块中定义 MCP 工具(如 middle_time
  5. #[tool_handler] impl 块实现 ServerHandler trait,提供服务器信息和生命周期回调

构建和运行

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: 检查以下几点:

  1. 可执行文件路径是否正确
  2. 文件是否有执行权限 (chmod +x prometheus-mcp-server)
  3. 查看 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
相关推荐
FAFU_kyp2 小时前
Rust 结构体(struct)
开发语言·后端·rust
分布式存储与RustFS3 小时前
MinIO社区版“躺平”,RustFS能接棒吗?
rust·开源项目·对象存储·企业存储·rustfs·minio国产化替代
rustfs3 小时前
使用 RustFS和 Arq,打造 PC 数据安全备份之道
分布式·docker·云原生·rust·开源
m0_748252383 小时前
Foundation 表格的基本用法
开发语言·后端·rust
古城小栈3 小时前
Rust unsafe 一文全功能解析
开发语言·后端·rust
亲爱的非洲野猪4 小时前
基于 MCP 构建智能文档分析系统:技术实现详解
python·ai·mcp
Amos_Web4 小时前
Rust实战(五):用户埋点数据分析(前)
后端·架构·rust
古城小栈5 小时前
Rust 模式匹配 大合集
开发语言·后端·rust
古城小栈5 小时前
Rust 宏 !
算法·rust