MCP服务器实现

一个完整的Model Context Protocol (MCP)服务器实现,提供工具、资源和提示用于LLM集成。

  • by sudhirkumar-in
  • Rust
  • 本地部署
  • 更新于
在 GitHub 查看 gitsudhir/mcp-server-rust

使用说明

Rust-MCP服务器:一个完整的实现

Rust中功能齐全的模型上下文协议(MCP)服务器实现,为LLM集成提供工具、资源和提示。

目录

  1. 概述
  2. 特性
  3. 项目结构
  4. 先决条件
  5. 安装
  6. 建设项目
  7. 运行服务器
  8. 测试服务器
  9. API 参考
  10. 添加自定义工具
  11. 故障排除
  12. 安全注意事项

概述

此Rust MCP服务器实现了 模型上下文协议(MCP) 规范,实现LLM应用程序与外部工具、资源和知识库之间的无缝集成。

什么是MCP?

模型上下文协议是一个开放标准,允许:

  • LLM应用 连接到外部数据源和工具
  • 服务器 以标准化的方式公开功能(工具、资源、提示)
  • 安全集成 无需修改客户端应用程序

关键利益

✅ 类型安全:利用Rust的类型系统确保安全
✅ 高性能:与Tokio异步/等待以实现高并发
✅ 模块化:易于添加自定义工具和资源
✅ 安全:内置验证和错误处理
✅ 基于标准:作为子流程进行简单部署


特性

内置工具

  1. 问候工具 (greet)

    • 用个性化信息问候用户
    • 输入: name (字符串)
    • 输出:问候语
  2. BMI计算器工具 (calculate-bmi)

    • 计算体重指数
    • 输入: weightKg (数字), heightM (编号)
    • 输出:计算的BMI值
  3. 天气工具 (fetch-weather)

    • 获取天气信息(模拟)
    • 输入: city (字符串)
    • 输出:天气数据(温度、条件、湿度等)

内置资源

  1. 应用程序配置 (config://app)
    • 提供应用程序元数据和设置
    • 返回JSON配置

内置提示

  1. 代码审查 (review-code)
    • 为LLM生成检查代码的提示
    • 论据: code (必填), focus (可选:性能、安全性、风格、通用性)

协议支持

  • ✅ 符合JSON-RPC 2.0标准
  • ✅ 标准传输(换行符分隔的JSON)
  • ✅ 使用标准错误代码进行正确的错误处理
  • ✅ 记录到stderr
  • ✅ 协议版本控制(2024-11-05)

项目结构

mcp-server-rust/
├── Cargo.toml                          # Project manifest
├── README.md                           # This file
├── src/
│   ├── main.rs                         # Entry point
│   ├── lib.rs                          # Library exports
│   ├── server.rs                       # MCP server implementation
│   ├── tools/
│   │   ├── mod.rs                      # Tool definitions
│   │   ├── greeting_tool.rs            # Greeting tool implementation
│   │   ├── calculator_tool.rs          # BMI calculator tool
│   │   └── weather_tool.rs             # Weather tool (simulated)
│   ├── resources/
│   │   ├── mod.rs                      # Resource definitions
│   │   ├── config_resource.rs          # App config resource
│   │   └── file_resource.rs            # File-based resource
│   ├── prompts/
│   │   ├── mod.rs                      # Prompt definitions
│   │   └── code_review_prompt.rs       # Code review prompt
│   ├── transport/
│   │   ├── mod.rs                      # Transport trait
│   │   └── stdio.rs                    # Stdio implementation
│   └── utils/
│       ├── mod.rs                      # Utility modules
│       ├── logger.rs                   # Logging utilities
│       └── error.rs                    # Error types
└── data/
    └── (sample data files)

先决条件

系统要求

  • 操作系统:macOS、Linux或Windows(带WSL2)
  • 随机存取存储器:最低512 MB(建议2 GB)
  • 磁盘空间:1 GB(主要用于依赖项)

所需软件

  1. 锈 (1.70或更高版本)

    # Install from https://rustup.rs/
    curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
    
  2. 货物 (随Rust一起提供)

    cargo --version
    
  3. Git

    git --version
    

验证安装

rustc --version
cargo --version

安装

步骤1:克隆存储库

git clone https://github.com/gitsudhir/mcp-server-rust.git
cd mcp-server-rust

或者从头开始创建一个新项目:

cargo new mcp-server-rust
cd mcp-server-rust

第二步:复制文件

将所有提供的源文件复制到 src/ 目录,如“项目结构”部分所示。

步骤3:更新Cargo.toml

确保您的 Cargo.toml 将提供的配置与所有必需的依赖项相匹配。

步骤4:验证依赖关系

cargo check

这将下载并验证所有依赖关系,而无需构建。


建设项目

开发版本

# Build with debug information (slower, larger binary)
cargo build

# Output: target/debug/mcp-server-rust

发布版本(推荐)

# Build optimized binary (faster execution)
cargo build --release

# Output: target/release/mcp-server-rust

构建验证

# Check without building
cargo check

# Run tests
cargo test

# View warnings
cargo clippy

运行服务器

基本执行

# Using debug binary
./target/debug/mcp-server-rust

# Using release binary
./target/release/mcp-server-rust

使用日志记录

# Enable debug logging
RUST_LOG=debug ./target/release/mcp-server-rust

# Enable specific module logging
RUST_LOG=rust_mcp_server::server=debug,rust_mcp_server::transport=debug ./target/release/mcp-server-rust

# All logs
RUST_LOG=trace ./target/release/mcp-server-rust

创建外壳包装器

为了更容易调用,创建一个shell脚本:

#!/bin/bash
exec /full/path/to/mcp-server-rust "$@"

使其可执行:

chmod +x mcp-server.sh

测试服务器

JSON-RPC手动测试

服务器运行时在另一个终端中进行测试:

初始化连接

echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"TestClient","version":"1.0.0"}}}' | ./target/release/mcp-server-rust

调用工具

echo '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"greet","arguments":{"name":"Alice"}}}' | ./target/release/mcp-server-rust

列出工具

echo '{"jsonrpc":"2.0","id":3,"method":"tools/list"}' | ./target/release/mcp-server-rust

计算BMI

echo '{"jsonrpc":"2.0","id":4,"method":"tools/call","params":{"name":"calculate-bmi","arguments":{"weightKg":70,"heightM":1.75}}}' | ./target/release/mcp-server-rust

获取天气

echo '{"jsonrpc":"2.0","id":5,"method":"tools/call","params":{"name":"fetch-weather","arguments":{"city":"San Francisco"}}}' | ./target/release/mcp-server-rust

获取提示

echo '{"jsonrpc":"2.0","id":6,"method":"prompts/get","params":{"name":"review-code","arguments":{"code":"fn main() { println!(\"Hello!\"); }","focus":"performance"}}}' | ./target/release/mcp-server-rust

MCP检验员测试

官方MCP Inspector工具允许交互式测试:

  1. 安装检查器:

    npm install -g @modelcontextprotocol/inspector
    
  2. 运行服务器:

    ./target/release/mcp-server-rust
    
  3. 运行检查器 (在另一个终端中):

    mcp-inspector stdio ./target/release/mcp-server-rust
    
  4. 在浏览器和测试工具中以交互方式打开检查器UI。

自动化测试

# Run built-in tests
cargo test

# Run with output
cargo test -- --nocapture

# Run specific test
cargo test test_name -- --nocapture

API 参考

JSON-RPC方法

1. initialize

目的:初始化MCP连接

请求:

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "initialize",
  "params": {
    "protocolVersion": "2024-11-05",
    "capabilities": {},
    "clientInfo": {
      "name": "ClientName",
      "version": "1.0.0"
    }
  }
}

响应:

{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "protocolVersion": "2024-11-05",
    "capabilities": {
      "tools": {},
      "resources": {},
      "prompts": {}
    },
    "serverInfo": {
      "name": "RustMcpServer",
      "version": "1.0.0"
    }
  }
}

2. tools/list

目的:列出可用工具

请求:

{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "tools/list"
}

响应:

{
  "jsonrpc": "2.0",
  "id": 2,
  "result": {
    "tools": [
      {
        "name": "greet",
        "description": "Greets a person with a friendly message",
        "inputSchema": {
          "type": "object",
          "properties": {
            "name": {
              "type": "string",
              "description": "The name of the person to greet"
            }
          },
          "required": ["name"]
        },
        "annotations": {
          "title": "Greet Tool",
          "readOnlyHint": true
        }
      }
    ]
  }
}

3. tools/call

目的:调用工具

请求:

{
  "jsonrpc": "2.0",
  "id": 3,
  "method": "tools/call",
  "params": {
    "name": "greet",
    "arguments": {
      "name": "Alice"
    }
  }
}

响应(成功):

{
  "jsonrpc": "2.0",
  "id": 3,
  "result": {
    "content": [
      {
        "type": "text",
        "text": "Hello, Alice! Welcome to MCP."
      }
    ],
    "isError": false
  }
}

响应(错误):

{
  "jsonrpc": "2.0",
  "id": 3,
  "error": {
    "code": -32602,
    "message": "Invalid params: Missing 'name' parameter"
  }
}

4. resources/list

目的:列出可用资源

请求:

{
  "jsonrpc": "2.0",
  "id": 4,
  "method": "resources/list"
}

响应:

{
  "jsonrpc": "2.0",
  "id": 4,
  "result": {
    "resources": [
      {
        "uri": "config://app",
        "name": "Application Configuration",
        "description": "Current application configuration",
        "mimeType": "application/json"
      }
    ]
  }
}

5. resources/read

目的:阅读资源

请求:

{
  "jsonrpc": "2.0",
  "id": 5,
  "method": "resources/read",
  "params": {
    "uri": "config://app"
  }
}

响应:

{
  "jsonrpc": "2.0",
  "id": 5,
  "result": {
    "contents": [
      {
        "uri": "config://app",
        "mimeType": "application/json",
        "text": "{\"appName\": \"Rust MCP Server\", \"version\": \"1.0.0\", ...}"
      }
    ]
  }
}

6. prompts/list

目的:列出可用提示

请求:

{
  "jsonrpc": "2.0",
  "id": 6,
  "method": "prompts/list"
}

响应:

{
  "jsonrpc": "2.0",
  "id": 6,
  "result": {
    "prompts": [
      {
        "name": "review-code",
        "description": "Generates a prompt to ask the LLM to review code",
        "arguments": [
          {
            "name": "code",
            "description": "The code snippet to review",
            "required": true
          },
          {
            "name": "focus",
            "description": "Optional area of focus",
            "required": false
          }
        ]
      }
    ]
  }
}

7. prompts/get

目的:获取提示

请求:

{
  "jsonrpc": "2.0",
  "id": 7,
  "method": "prompts/get",
  "params": {
    "name": "review-code",
    "arguments": {
      "code": "fn main() { println!(\"Hello!\"); }",
      "focus": "performance"
    }
  }
}

响应:

{
  "jsonrpc": "2.0",
  "id": 7,
  "result": {
    "description": "Requesting performance review for code snippet",
    "messages": [
      {
        "role": "user",
        "content": [
          {
            "type": "text",
            "text": "Please review the following code for potential issues and suggest improvements, focusing specifically on performance:\n\n```\nfn main() { println!(\"Hello!\"); }\n```"
          }
        ]
      }
    ]
  }
}

添加自定义工具

步骤1:创建工具模块

use super::{Tool, CallToolResult, TextContent, ToolHandler};
use serde_json::{json, Value};
use async_trait::async_trait;
use crate::utils::{Result, Error, Logger};

pub struct CustomTool {
    logger: Logger,
}

impl CustomTool {
    pub fn new() -> Self {
        Self {
            logger: Logger::new("CustomTool"),
        }
    }

    pub fn tool_definition() -> Tool {
        Tool {
            name: "custom-tool".to_string(),
            description: "Description of your custom tool".to_string(),
            input_schema: json!({
                "type": "object",
                "properties": {
                    "param1": {
                        "type": "string",
                        "description": "First parameter"
                    },
                    "param2": {
                        "type": "number",
                        "description": "Second parameter"
                    }
                },
                "required": ["param1"]
            }),
            annotations: Some(json!({
                "title": "Custom Tool",
                "readOnlyHint": true
            })),
        }
    }
}

impl Default for CustomTool {
    fn default() -> Self {
        Self::new()
    }
}

#[async_trait]
impl ToolHandler for CustomTool {
    async fn call(&self, arguments: Value) -> Result<CallToolResult> {
        let param1 = arguments
            .get("param1")
            .and_then(|v| v.as_str())
            .ok_or_else(|| Error::InvalidParams("Missing 'param1'".to_string()))?;

        let param2 = arguments
            .get("param2")
            .and_then(|v| v.as_f64())
            .unwrap_or(0.0);

        self.logger.debug_with_context(
            "Tool called",
            &format!("param1={}, param2={}", param1, param2),
        );

        // Your custom logic here
        let result = format!("Processed: {} and {}", param1, param2);

        Ok(CallToolResult::success(vec![TextContent::new(result)]))
    }
}

步骤2:在模块中注册

增添 src/tools/mod.rs:

pub mod custom_tool;
pub use custom_tool::CustomTool;

步骤3:添加到服务器

在 src/server.rs,更新 handle_tools_list:

async fn handle_tools_list(&self, _message: &Value) -> Result<Value> {
    self.logger.debug("Listing tools");

    let tools = vec![
        GreetingTool::tool_definition(),
        CalculatorTool::tool_definition(),
        WeatherTool::tool_definition(),
        CustomTool::tool_definition(),  // Add this
    ];

    Ok(json!({
        "tools": tools
    }))
}

在 handle_tools_call,添加匹配臂:

"custom-tool" => {
    let handler = CustomTool::new();
    handler.call(arguments).await?
}

步骤4:重建和测试

cargo build --release

# Test
echo '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"custom-tool","arguments":{"param1":"test","param2":42}}}' | ./target/release/mcp-server-rust

故障排除

问题:服务器无法启动

# Check if executable exists
ls -la target/release/mcp-server-rust

# Try building again
cargo clean
cargo build --release

# Check for errors
cargo check

问题:连接被拒绝

  1. 验证服务器是否正在运行
  2. 检查是否有其他进程正在使用该端口
  3. 查看日志:
    RUST_LOG=trace ./target/release/mcp-server-rust
    

问题:找不到工具

  1. 验证工具是否已在中注册 handle_tools_list
  2. 检查工具名称是否完全匹配
  3. 验证匹配臂是否插入 handle_tools_call

问题:无效参数错误

  1. 检查JSON-RPC请求中的参数名称
  2. 验证类型(字符串与数字)
  3. 看看工具 inputSchema

问题:无输出/冻结

  1. 检查服务器是否正在等待输入
  2. 验证stdin/stdout未被阻止
  3. 启用日志记录:
    RUST_LOG=trace ./target/release/mcp-server-rust
    

启用调试日志记录

# All modules
RUST_LOG=debug ./target/release/mcp-server-rust

# Specific module
RUST_LOG=rust_mcp_server::server=debug ./target/release/mcp-server-rust

# Very detailed
RUST_LOG=trace ./target/release/mcp-server-rust

使用MCP检查员进行测试

# Terminal 1: Start server
./target/release/mcp-server-rust

# Terminal 2: Run inspector
npx @modelcontextprotocol/inspector stdio ./target/release/mcp-server-rust

安全注意事项

输入验证

✅ 所有工具参数都使用JSON模式进行验证
✅ 检查文件路径是否有遍历尝试
✅ 刀具参数经过类型检查

输出消毒

✅ 工具结果安全地序列化为JSON
✅ 无原始命令执行
✅ 错误消息不公开内部详细信息

最佳实践

  1. 从不信任客户端输入

    // BAD
    let path = arguments.get("file").unwrap();
    
    // GOOD
    let path = arguments
        .get("file")
        .and_then(|v| v.as_str())
        .ok_or_else(|| Error::InvalidParams("..."))?;
    
  2. 验证文件路径

    fn validate_path(&self, filename: &str) -> Result<PathBuf> {
        let requested = self.base_dir.join(filename);
        let resolved = std::fs::canonicalize(&requested)?;
        if !resolved.starts_with(&self.base_dir) {
            return Err(Error::ResourceError("Path traversal".into()));
        }
        Ok(resolved)
    }
    
  3. 安全地处理错误

    match operation() {
        Ok(result) => Ok(CallToolResult::success(...)),
        Err(e) => {
            self.logger.error(&e.to_string());  // Log internally
            Ok(CallToolResult::error("Operation failed"))  // Generic response
        }
    }
    
  4. 设置资源限制

    const MAX_RESULT_SIZE: usize = 10_000_000;  // 10MB
    if result.len() > MAX_RESULT_SIZE {
        return Err(Error::InternalError("Result too large".into()));
    }
    

高级主题

创建HTTP传输

虽然当前的实现使用Stdio,但您可以添加HTTP支持:

use crate::utils::Result;
use async_trait::async_trait;
use axum::{extract::Json, http::StatusCode, routing::post, Router};
use serde_json::Value;

#[async_trait]
pub async fn http_handler(
    Json(payload): Json<Value>,
) -> (StatusCode, Json<Value>) {
    // Handle JSON-RPC request
    (StatusCode::OK, Json(payload))
}

pub fn create_router() -> Router {
    Router::new()
        .route("/mcp", post(http_handler))
}

添加持久状态

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

pub struct ServerState {
    data: Arc<RwLock<HashMap<String, Value>>>,
}

impl ServerState {
    pub async fn get(&self, key: &str) -> Option<Value> {
        self.data.read().await.get(key).cloned()
    }
    
    pub async fn set(&self, key: String, value: Value) {
        self.data.write().await.insert(key, value);
    }
}

异步工具执行

#[async_trait]
impl ToolHandler for AsyncTool {
    async fn call(&self, arguments: Value) -> Result<CallToolResult> {
        // Can use tokio::time::sleep, reqwest, etc.
        let result = tokio::time::timeout(
            std::time::Duration::from_secs(30),
            self.perform_async_work()
        ).await??;
        
        Ok(CallToolResult::success(vec![TextContent::new(result)]))
    }
}

贡献

欢迎投稿!拜托:

  1. 分叉存储库
  2. 创建要素分支
  3. 进行更改
  4. 添加测试
  5. 提交拉取请求

许可证

MIT许可证-有关详细信息,请参阅许可证文件


资源


常见问题解答

Q: 我可以运行多个MCP服务器吗?
A: 是的!每个应用程序都可以管理多个客户端-服务器连接。

Q: 这个生产准备好了吗?
A: 核心是稳定的,但在生产使用之前要审查安全考虑因素。

Q: 我可以添加数据库集成吗?
A: 当然!在工具处理程序中使用sqlx、tokio postgres等。

Q: 如何调试工具?
A: 启用日志记录 RUST_LOG=debug 并使用MCP检查器工具。


支持

对于问题和疑问:

  • 查看此README和示例
  • 启用调试日志
  • 审查MCP规范
  • 打开GitHub问题

最后更新: 2026-02-13
版本: 1.0.0
状态:稳定