MCP工具服务器框架

一个用于构建MCP(模型上下文协议)工具服务器的轻量级C++框架,支持JSON-RPC 2.0协议、工具注册、模式生成和调度。

  • by jkerdels
  • C++
  • 本地部署
  • 1 星标
  • 更新于
在 GitHub 查看 jkerdels/tiny-mcp

使用说明

微型mcp

用于构建的最小C++框架 主控程序 (模型上下文协议)工具服务器。它处理JSON-RPC 2.0协议、工具注册、模式生成和调度,因此您可以专注于编写工具。

特性

  • 类型安全工具登记 --将工具参数定义为 std::tuple 的 ToolParam<> 类型;输入模式在编译时自动生成。
  • JSON-RPC 2.0 --初始化握手, tools/list, tools/call,并内置了错误处理功能。
  • stdio传输 --从stdin读取JSON-RPC,将响应写入stdout。没有HTTP,没有套接字。
  • 单一依赖关系 --只需要 nlohmann/json,通过CMake自动获取。

快速开始

1.将微型mcp添加到您的项目中

在你的 CMakeLists.txt:

include(FetchContent)

FetchContent_Declare(
    tiny_mcp
    GIT_REPOSITORY https://github.com/jkerdels/tiny-mcp.git
    GIT_TAG        main
)
FetchContent_MakeAvailable(tiny_mcp)

target_link_libraries(your-server PRIVATE tiny-mcp::tiny-mcp)

2.编写服务器

#include <iostream>
#include <tiny-mcp/mcp_server.h>

int main() {
    McpToolServer server("my-server", "0.1.0");

    // Define a tool with typed parameters
    using GreetParams = std::tuple<
        ToolParam<"name", "Name to greet", std::string>
    >;

    server.tools().register_tool<GreetParams>(
        "greet",
        "Say hello to someone",
        [](GreetParams& p) -> std::expected<std::string,std::string> {
            return "Hello, " + std::string(std::get<0>(p)) + "!";
        }
    );

    // Main loop: read JSON-RPC from stdin, write responses to stdout
    json message;
    try {
        while (std::cin >> message) {
            auto response = server.handle_message(message);
            if (response) {
                std::cout << *response << "\n";
                std::cout.flush();
            }
        }
    } catch (const json::parse_error&) {
        // nlohmann::json throws parse_error on EOF instead of setting eofbit
    }
    return 0;
}

3.用克劳德代码注册

claude mcp add --scope user --transport stdio my-server -- /path/to/your-server

这使得服务器在所有项目中都可用。使用 --scope project 通过项目的 .mcp.json。您可以通过键入来验证它是否已注册 /mcp 克劳德代码内部。

定义工具

工具使用参数元组和回调进行注册:

using Params = std::tuple<
    ToolParam<"query",  "Search query",              std::string>,
    ToolParam<"limit",  "Max results",               int>,
    ToolParam<"exact",  "Require exact match",       bool>
>;

server.tools().register_tool<Params>(
    "search",
    "Search for items",
    [](Params& p) -> std::expected<std::string,std::string> {
        auto& query = std::get<0>(p);  // std::string
        auto& limit = std::get<1>(p);  // int
        auto& exact = std::get<2>(p);  // bool
        // ... your logic here ...
        if (query.value.empty())
            return std::unexpected("query must not be empty");
        return "results";
    }
);

工具回调返回 std::expected<std::string,std::string>.返回一个plain std::string 成功(隐含转换),或 std::unexpected("reason") 以向主叫代理发回工具错误信号。

支持的参数类型: std::string, int, bool, double.

输入模式(JSON模式)是从以下内容自动生成的 ToolParam 声明——不需要手动JSON。

反向通道通知

微型mcp支持 服务器发起的事件:服务器可以将消息推送到代理,而无需代理轮询。这是通过利用长轮询模式来实现的——后台子代理调用 backchannel_event 该工具会一直阻塞,直到服务器有东西要交付。

启用反向通道

// In your server setup, before entering the main loop:
server.enable_backchannel();          // unbounded queue, writes to stdout
// or
server.enable_backchannel(out, 64);  // ring-buffer of 64 events, custom ostream

这会自动注册两个工具:

  • backchannel_event --长民意调查工具。代理调用此命令并等待。
  • backchannel_usage --返回代理的使用说明。

从服务器发出事件

server.emit_backchannel_event("something happened");
  • 如果 backchannel_event 呼叫处于挂起状态,立即写入响应并清除挂起的呼叫。
  • 如果没有待处理的呼叫,则消息被排队。下一个 backchannel_event 打电话给 include_queued=true (默认)将清空队列并立即返回。

代理侧模式

代理应启动一个调用的后台子代理 backchannel_event 然后等待。当它返回时,前台代理处理事件并重新启动后台子代理。这 backchannel_usage 该工具详细描述了这种模式。

权限:Claude Code子代理不会自动继承MCP工具权限。如果没有明确的分配,背景子代理的 backchannel_event 呼叫将被拒绝。将工具(或服务器上所有工具的通配符)添加到项目的 .claude/settings.local.json:

{
  "permissions": {
    "allow": ["mcp__your-server-name__*"]
  }
}

环形缓冲区语义

max_queue_size (默认值0=无界)为队列设置上限。当已满时,最旧的条目将被删除(最旧的删除策略)。

示例

看 examples/notes/ 一个完整的工作示例:一个简单的笔记存储服务器 add_note, get_note,以及 list_notes 工具。

cd examples/notes
mkdir build && cd build
cmake .. && cmake --build .

需求

  • C++23
  • CMake 3.14+