模型上下文协议SDK

一个现代C++20 SDK,用于实现模型上下文协议(MCP),支持工具调用、资源访问、提示管理等核心功能,适用于编辑器、IDE、代理和高吞吐量服务器。

  • by Neumann-Labs
  • C++
  • 本地部署
  • 64 星标
  • 更新于
在 GitHub 查看 Neumann-Labs/mcp-cpp

使用说明

mcp-cpp

一个现代的C++20 SDK 模型上下文协议 (MCP),目标方案修订 2025-11-25.

状态: 贝塔。线格式锁定在官方MCP规范中;C++ API在1.0之前可能仍有改进。

为什么

LLM应用程序越来越需要一种统一的方式来与工具、资源和 及时的供应商。MCP就是那个协议;该SDK旨在成为一个干净、快速、, 符合规范的C++实现, 代理、本地应用程序和高吞吐量服务器。

设计目标:

  • 规格忠实。 字段名、方法名和行为与 官方TypeScript模式 逐字逐句。
  • C++20的习语。 RAII,价值语义, std::variant 对于总和类型, 异步结果的未来,没有继承层次结构,组合将 同上
  • 表面小,杠杆大。 有重点的公共API;大部分工作 发生在几个名字很好的类型后面。
  • 生产准备就绪。 消毒剂清洁,必须放在安全的地方,没有 热路径上的隐藏分配。

0.1中有什么

功能 服务器 客户端 备注
初始化/能力协商 ✅ ✅ 规格2025-11-25
工具(列表、调用) ✅ ✅ 文本/图像/音频内容块
资源(列表、阅读、模板、订阅/取消订阅) ✅ ✅ 文本+base64 blob内容
提示(列表,获取) ✅ ✅ 带有内容块的键入邮件
取样(sampling/createMessage) ✅ 发起人 ✅ 响应者 服务器发起LLM调用
根(roots/list) ✅ 发起人 ✅ 响应者 客户端文件系统作用域
竣工(completion/complete) ✅ ✅ 自动补全建议
取消(notifications/cancelled) ✅ ✅ 钢丝水平支撑
进展(notifications/progress) ✅ ✅ 类型化令牌+处理程序
日志记录(notifications/message, logging/setLevel) ✅ ✅ RFC-5424级别
Ping(ping) ✅ ✅ 双向活性
分页 ✅ ✅ 可配置页面大小
stdio 运输 ✅ ✅ 规范正确的框架
可流式HTTP传输 ✅ ✅ POST+SSE GET流+会话ID
任务(tasks/get/result/list/cancel,状态通知) ✅ ✅ 增强 tools/call 通过 task 场;规格2025-11-25
激励(elicitation/create,表单+url模式) ✅ 发起人 ✅ 应答器 规范2025-11-25
OAuth 2.1授权(HTTP) ✅ ✅ 承载+RFC 9728受保护的资源元数据

快速启动

最小服务器

#include <mcp/mcp.hpp>

int main() {
    mcp::Server server{
        mcp::Implementation{.name = "calc", .version = "1.0.0"},
    };

    server.tool("add",
        nlohmann::json{
            {"type", "object"},
            {"properties", {
                {"a", {{"type", "number"}}},
                {"b", {{"type", "number"}}},
            }},
            {"required", nlohmann::json::array({"a", "b"})},
        },
        [](const nlohmann::json& args) -> mcp::CallToolResult {
            const double a = args.at("a").get<double>();
            const double b = args.at("b").get<double>();
            return {
                .content = { mcp::TextContent{.text = std::to_string(a + b)} },
            };
        });

    server.run(std::make_unique<mcp::StdioTransport>());
}

从支持MCP服务器的主机上运行(Claude Desktop、Cursor、官方 通过指向得到的二进制文件。Stderr是你的 诊断;stdout是为JSON-RPC流保留的。

最小客户

#include <mcp/mcp.hpp>

int main() {
    auto pair = /* spawn the server, wire its stdio to a transport */;

    mcp::Client client{
        mcp::Implementation{.name = "my-app", .version = "0.1.0"},
    };
    client.connect(std::move(pair.transport));

    auto info = client.initialize().get();
    std::cout << "connected to " << info.server_info.name << "\n";

    auto tools = client.list_tools().get();
    for (const auto& t : tools.tools) {
        std::cout << " - " << t.name << "\n";
    }

    auto out = client.call_tool("add",
                                nlohmann::json{{"a", 2}, {"b", 3}}).get();
    if (auto* text = std::get_if<mcp::TextContent>(&out.content[0])) {
        std::cout << "result: " << text->text << "\n";
    }
}

通过HTTP托管

同一服务器,作为可流式HTTP端点公开。多个客户端 每个人都有自己的 Mcp-Session-Id-关键会话。

mcp::HttpServerHost host{
    mcp::Implementation{.name = "calc", .version = "1.0"},
    mcp::HttpServerHost::Options{
        .host            = "127.0.0.1",
        .port            = 8080,
        .path            = "/mcp",
        .allowed_origins = {"https://example.com"},  // DNS-rebind defense
    },
    [](mcp::Server& s) {
        s.tool("add", schema, handler);
    },
};
host.start();
// ... wait for shutdown signal ...
host.stop();

客户端连接到它的方式与连接到stdio服务器的方式相同, 但随着 HttpClientTransport 而不是 StdioTransport:

mcp::HttpClientTransport::Options topts;
topts.url = "http://localhost:8080/mcp";
mcp::Client client{mcp::Implementation{.name = "my-app", .version = "0.1"}};
client.connect(std::make_unique<mcp::HttpClientTransport>(topts));
auto info = client.initialize().get();
auto out  = client.call_tool("add", {{"a", 1}, {"b", 2}}).get();

两者 examples/http_calculator_server (绑定127.0.0.1:8080通过 默认值)和stdio examples/calculator_server 船与 建造。

一个不平凡的演示:助手的持久笔记

examples/mcp_notes_server 是一个SQLite+FTS5草稿行,它提供 Claude(或任何MCP客户端)持久、全文可搜索内存 跨届会议。将其插入克劳德桌面/Claude Code并询问 “将我的Postgres-prod连接字符串保存在db.prod下”--它是 下次你打开聊天时。搜索“postgres”,你会得到一个 BM25排名片段命中率。Glob删除通过规范 启发式原语,因此人类之前会得到一个是/否提示 任何东西都被抹去了。

建造它(libsqlite3-dev 在Linux上,随macOS附带):

cmake -S . -B build -DMCP_BUILD_EXAMPLES=ON
cmake --build build --target mcp_notes_server

看 examples/mcp_notes_server/README.md 为了电线。

服务器发起的LLM调用(采样)

一种常见的代理模式是让工具要求宿主应用程序进行 代表其发出法学硕士电话。

server.tool("ask", schema,
    [&server](const nlohmann::json& args) -> mcp::CallToolResult {
        auto resp = server.sample(mcp::CreateMessageRequestParams{
            .messages = {
                mcp::SamplingMessage{
                    .role    = mcp::Role::user,
                    .content = mcp::TextContent{.text = args["q"]},
                },
            },
            .max_tokens = 512,
        }).get();
        return {
            .content = { mcp::TextContent{
                .text = std::get<mcp::TextContent>(resp.content).text,
            }},
        };
    });

客户端插入一个执行实际LLM调用的采样处理程序:

client.set_sampling_handler(
    [](const mcp::CreateMessageRequestParams& req) -> mcp::CreateMessageResult {
        // ...invoke your LLM provider with `req.messages` etc...
        return {
            .role    = mcp::Role::assistant,
            .content = mcp::TextContent{.text = "..."},
            .model   = "claude-3-5-sonnet-20241022",
        };
    });

Session在工作线程上分派入站请求,因此调用 server.sample(...).get() 从工具处理程序内部来看是安全的——它不是 僵局。

建筑物

cmake -B build -G Ninja
cmake --build build
ctest --test-dir build --output-on-failure

构建选项

选项 默认值 效果
MCP_BUILD_TESTS ON 构建GTest测试套件。
MCP_BUILD_EXAMPLES ON 构建示例服务器/客户端。
MCP_WARNINGS_AS_ERRORS ON* 将警告升级为错误(仅限顶级)。
MCP_USE_SYSTEM_DEPS 关闭 find_package 而不是 FetchContent.
MCP_ENABLE_HTTP ON 构建 mcp::http 目标(流式HTTP传输,cpp-httplib+OpenSSL)。
MCP_HTTP_NO_TLS OFF 构建 mcp::http 没有OpenSSL(仅纯文本)-适用于不得链接第二个OpenSSL的主机(例如游戏引擎)。
MCP_ENABLE_ASAN 关闭 -fsanitize=address,undefined.
MCP_ENABLE_TSAN 关闭 -fsanitize=thread.
MCP_ENABLE_COVERAGE 关闭 --coverage 对于gcov/llvm-cov。

*当这是顶级项目时,默认为ON;通过以下方式消费时关闭 add_subdirectory.

消耗图书馆

CMake find_package

之后 cmake --install build,下游项目可以做到:

find_package(mcp REQUIRED)
target_link_libraries(my_app PRIVATE mcp::mcp)   # stdio + core: no OpenSSL

地心末日 mcp::mcp 目标仅取决于 nlohmann_json 并且不携带TLS 附属国。使用流式HTTP传输(HttpServerHost / HttpClientTransport),链接单独 mcp::http 相反,它会拉动目标 在 mcp::mcp 加上cpp-httplib/OOpenSSL:

target_link_libraries(my_app PRIVATE mcp::http)  # HTTP transport (needs MCP_ENABLE_HTTP)

add_subdirectory /获取内容

include(FetchContent)
FetchContent_Declare(mcp
    GIT_REPOSITORY https://github.com/Neumann-Labs/mcp-cpp.git
    GIT_TAG        main)
FetchContent_MakeAvailable(mcp)

target_link_libraries(my_app PRIVATE mcp::mcp)   # or mcp::http for HTTP

60秒内完成架构

                  +-----------------+
   application -> | Server / Client | <- public façade
                  +-----------------+
                          |
                  +-----------------+
                  |     Session     | <- JSON-RPC dispatch +
                  +-----------------+    request/response correlation
                          |
                  +-----------------+
                  |   Transport     | <- byte shovel (StdioTransport,
                  +-----------------+    Streamable HTTP, in-memory pair)
                          |
                          v
                       wire
  • 运输 是一个小型抽象界面:它铲出框架;会议 解析它们。
  • 会话 拥有请求id生成器、待定请求映射、 请求/通知调度表和超时扫描。都一样 线路两侧的类——服务器和客户端只是注册不同 处理程序和调用不同的便利方法。
  • 服务器/客户端 是薄立面:它们将键入的C++值转换为 JSON-RPC框架和背面,暴露 tool() / resource() / prompt() / sample() / list_tools() /并且各自拥有一个会话。

线程

  • 传输在自己的线程上读取并调用会话的 在消息回调时。
  • 入站 请求: 被分派到一个分离的工作线程,因此用户 处理程序本身可以在同一会话上发出进一步的请求 (例如。 server.sample(...).get() 从工具处理器内部)。 Session::close() 等那些工人做完再撕 成员下降。
  • 入站 通知 和 回应 直接在read线程上运行。
  • send_request / send_notification 从任何线程调用都是安全的。

许可证

Apache 2.0——请参阅 许可证.