Back to MCP directory
publicPublicdnsLocal runtime

sample-cpp-mcp-servers

C++实现的MCP Servers示例项目

article

README

🚀 mcp-sample-cpp-servers

这是一个用C++实现的MCP Servers示例项目,完整复制自MCP Servers入门文章中的C++实现。目前仅验证了标准输入输出的功能,由于目的是演示协议的使用,因此仅实现了对函数调用的支持。计划在博客上创建代码发布页面后删除此仓库(n个月后)。

🚀 快速开始

前提条件

确保已安装C++编译器(如gcc或MSVC)以及必要的开发库。

构建项目

将项目添加到IDE中并构建。

启动服务器

编译生成可执行文件后,在终端运行即可启动MCP服务器。

✨ 主要特性

  • 初始化MCP服务器并设置协议版本和服务器信息。
  • 注册一个名为evaluate-scores的工具,用于评估一组分数。
  • 实现了对evaluate-scores工具的调用处理逻辑,计算总分和平均分。
  • 针对Windows环境进行了二进制模式设置,以解决文件操作问题。

📦 安装指南

  1. 确保已安装C++编译器(如gcc或MSVC)以及必要的开发库。
  2. 将项目添加到IDE中并构建。
  3. 编译生成可执行文件后,在终端运行即可启动MCP服务器。

💻 使用示例

基础用法

# 发送工具列表请求
curl -X POST http://localhost:5000/tools/list

# 调用evaluate-scores工具
curl -X POST http://localhost:5000/tools/call \
     -H "Content-Type: application/json" \
     -d '{"tool":"evaluate-scores","params":{"scores":[1,2,3,4,5]}}'

输出说明

  • 工具列表请求返回已注册的工具信息。
  • 评估分数调用返回总分和平均分。

📚 详细文档

main.cpp内容

#include <iostream>
#include <fstream>
#include <chrono>
#include <unordered_map>
#include "mcp-server.hpp"

#if defined(_MSC_VER)
#include <fcntl.h>
#include <io.h>
#endif

/// <summary>
/// 获取表示时间的格式化字符串
/// </summary>
/// <returns>表示时间的格式化字符串</returns>
auto getTimeString() {
    const std::chrono::time_zone* tz = std::chrono::current_zone();
    return std::format("[{:%Y-%m-%d %H:%M:%S}]", tz->to_local(std::chrono::system_clock::now()));
}

int main() {
#if defined(_MSC_VER)
    // 为了解决Windows文本模式下的CRLF↔LF自动转换问题,将标准输入输出设置为二进制模式
    _setmode(_fileno(stdin), _O_BINARY);
    _setmode(_fileno(stdout), _O_BINARY);
#endif

    mcp::MCPServer server;

    // MCP服务器初始化
    server.request.onInitialize = [&](const mcp::InitializeRequest& params) {
        std::cerr << getTimeString() << "initialize" << std::endl;

        return mcp::InitializeResult{
            .protocolVersion = params.protocolVersion,
            .capabilities = {
                .tools = mcp::ServerCapabilities::ToolsInner{}
            },
            .serverInfo = {
                .name = "ABC游戏",
                .version = "1.0.0"
            }
        };
    };

    // MCP服务器初始化完成
    server.notification.onInitialized = [&]() {
        std::cerr << getTimeString() << "notifications/initialized" << std::endl;
    };

    // 工具注册
    server.request.tools.onList = [&]() {
        std::cerr << getTimeString() << "tools/list" << std::endl;

        return mcp::ListToolsResult{
            .tools = {
                {
                    .name = "evaluate-scores",
                    .description = "ABC游戏的分数评估",
                    // 相当于Zod中的以下JSON模式定义
                    // z.object({ score: z.number().min(0).describe("得分(点)") })
                    .inputSchema = nlohmann::json::object({
                        {"type", "object"},
                        {"properties", {
                            {"score", {
                                {"type", "number"},
                                {"minimum", 0},
                                {"description", "得分(点)"}
                            }}
                        }},
                        {"required", ["score"]}
                    })
                }
            }
        };
    };

    // 处理工具调用
    server.request.tools.onCall = [&](const std::string& toolName, const nlohmann::json& input) {
        std::cerr << getTimeString() << "tools/call " << toolName << " " << input.dump(4) << std::endl;

        if (toolName == "evaluate-scores") {
            if (!input["scores"].is_array()) {
                throw nlohmann::json::invalid_argument("Expected 'scores' to be an array");
            }

            size_t scoreCount = input["scores"].size();
            double total = 0.0;
            for (const auto& score : input["scores"]) {
                if (!score.is_number()) {
                    throw nlohmann::json::invalid_argument("Each score must be a number");
                }
                total += score.get<double>();
            }

            return nlohmann::json{
                {"total", static_cast<int64_t>(total)},
                {"average", total / scoreCount}
            };
        }

        throw nlohmann::json::invalid_argument("Unknown tool: " + toolName);
    };

    // 启动MCP服务器
    std::cerr << getTimeString() << "启动 MCP Server" << std::endl;
    server.start();

    while (true) {
        std::this_thread::sleep_for(std::chrono::seconds(1));
    }

    return 0;
}

代码说明

  • 代码结构:这是一个MCP服务器的完整实现,展示了如何初始化、注册工具以及处理工具调用。
  • 主要功能
    • 初始化MCP服务器并设置协议版本和服务器信息。
    • 注册一个名为evaluate-scores的工具,用于评估一组分数。
    • 实现了对evaluate-scores工具的调用处理逻辑,计算总分和平均分。
  • 平台特定代码:针对Windows环境进行了二进制模式设置,以解决文件操作问题。
help

Runtime guide

cloud

Hosted runtime

Hosted servers run from a provider-managed environment. You usually connect the MCP client to the hosted endpoint or follow the provider's authorization flow, without keeping a local process alive

  1. Open provider connection page
  2. Authorize or copy endpoint
  3. Connect from your MCP client
terminal

Local runtime / other methods

Local servers run on your own machine or infrastructure. You normally copy the server_config into your MCP client, install the required package, and provide env variables from env_schema when needed

  1. Copy server_config
  2. Install required package
  3. Fill env variables and restart client