A modern C++20 implementation of the Model Context Protocol (MCP), enabling seamless integration between LLM applications and external tools, resources, and prompts.
- Modern C++20: Coroutine-based asynchronous I/O with Boost.Asio.
- Shared or Static: The same public API is available through explicit CMake targets for either linkage model.
- Typed Protocol Models: Strongly typed models for the supported MCP surface, with
nlohmann/jsoninteroperability. - Flexible Transports: Native support for Stdio, WebSocket, and Streamable HTTP.
- Measured Interoperability: Official client and server conformance suites run in CI against a pinned
2025-11-25regression baseline, with unsupported scenarios kept visible. A green baseline means no drift, not that an SDK tier has been achieved.
The SDK combines a compiled client/server/transport runtime with header-based
protocol models and typed handler templates. Ordinary tool return values are
normalized into protocol-valid structured results, while complete raw
CallToolResult values use an explicit API. Interoperability and performance
claims are kept reproducible through the pinned conformance baseline and the
shared-workload benchmark adapters in benchmark/.
Package-manager routes are documented in the installation guide. The GitHub, Cloudsmith (APT/RPM), and AUR jobs read the exact published object back before reporting success. ConanCenter, Homebrew, and Chocolatey remain pending while their provider review or moderation is outstanding. Install only after the requested version appears at the destination; an upload or open registry PR is not availability proof.
Versions 0.x.y are stable releases unless suffixed with -rc.N, but each
pre-1.0 release has a distinct binary identity. Rebuild or relink consumers
when changing 0.x versions; see the installation guide for exact CMake and
runtime-package names.
The easiest way to use the SDK is via CMake's FetchContent:
include(FetchContent)
FetchContent_Declare(
mcp-cpp-sdk
GIT_REPOSITORY https://github.com/yurirocha15/mcp-cpp-sdk.git
# Replace with a verified release tag or full 40-character commit.
GIT_TAG <verified-tag-or-commit>
)
FetchContent_MakeAvailable(mcp-cpp-sdk)
target_link_libraries(your_target PRIVATE mcp::sdk)#include <mcp/mcp.hpp>
int main() {
mcp::ServerCapabilities capabilities;
capabilities.tools = mcp::ServerCapabilities::ToolsCapability{};
mcp::Server server({"hello-server", "1.0.0"}, capabilities);
server.add_tool("hello", "Greets the user",
{{"type", "object"}, {"properties", {{"name", {{"type", "string"}}}}}},
[](const nlohmann::json& args) -> nlohmann::json {
return nlohmann::json{
{"message", "Hello, " + args["name"].get<std::string>() + "!"}};
});
server.run_http("127.0.0.1", 3000); // Serves http://127.0.0.1:3000/mcp
}#include <mcp/client/client.hpp>
#include <mcp/transport/http_client.hpp>
#include <boost/asio/co_spawn.hpp>
#include <boost/asio/detached.hpp>
#include <boost/asio/io_context.hpp>
#include <iostream>
#include <memory>
int main() {
boost::asio::io_context io;
auto transport = std::make_shared<mcp::HttpClientTransport>(
io.get_executor(), "http://127.0.0.1:3000/mcp");
mcp::Client client(transport, io.get_executor());
boost::asio::co_spawn(io, [&]() -> mcp::Task<void> {
co_await client.connect("my-client", "1.0.0");
nlohmann::json arguments{{"name", "World"}};
auto result = co_await client.call_tool("hello", arguments);
std::cerr << nlohmann::json(result).dump(2) << '\n';
client.close();
}, boost::asio::detached);
io.run();
}Note the named arguments variable. See Compiler
Notes for why it is not built inline.
Resources and prompts use the same typed-handler model as tools: provide the
protocol metadata (mcp::Resource, mcp::ResourceTemplate, or mcp::Prompt)
and a handler whose input and output are serializable protocol types. See the
stdio server example for complete,
compiled registrations.
Async handlers have access to a Context for real-time interaction:
server.add_tool<nlohmann::json, nlohmann::json>("long_task", "A task with progress", schema,
[](mcp::Context& ctx, const nlohmann::json& args) -> mcp::Task<nlohmann::json> {
co_await ctx.log_info("Starting work...");
co_await ctx.report_progress(50, 100);
co_return nlohmann::json{{"status", "done"}};
});GCC 12 and GCC 13 crash with an internal compiler error when a co_await
expression contains an initializer list whose elements have non-trivial
destructors. GCC 13 is the default compiler on Ubuntu 24.04, so this is easy to
hit on a stock toolchain. The error looks like this with GCC 13.3 (GCC 12.4
reports line 10556), and names the closing brace of the enclosing lambda rather
than the offending argument:
internal compiler error: in build_special_member_call, at cp/call.cc:11096
Build the container into a named variable first:
// Crashes GCC 12 and GCC 13
auto result = co_await client.call_tool("hello", nlohmann::json{{"name", "World"}});
auto prompt = co_await client.get_prompt("greet", std::map<std::string, std::string>{{"who", "you"}});
// Compiles
nlohmann::json arguments{{"name", "World"}};
auto result = co_await client.call_tool("hello", arguments);The trigger is the initializer list, not the type, so it is not specific to
nlohmann::json: std::map<std::string, std::string>{{"a", "b"}} and
std::vector<std::string>{"a", "b"} crash the same way, while
std::vector<int>{1, 2, 3} and nlohmann::json::object() do not. Parentheses
do not help, because nlohmann::json({{"a", 1}}) still forms an initializer
list. Only hoisting the value out of the co_await expression avoids it.
This is a compiler defect rather than an SDK one, and no change to the SDK's signatures avoids it: taking the argument by value instead of by reference still crashes.
The contributing guide's Known Issues section carries the full case list, alongside the separate GCC 11 coroutine bug this codebase also works around.
For full guides, API reference, and integration details, visit our Documentation Site.
- Getting Started: Detailed installation and build instructions.
- Core Concepts: Deep dive into Tools, Resources, and Transports.
- Client App Integrations: How to connect your server to Claude, IDEs, and the MCP Inspector.
- Examples: Walkthrough of included example applications.
This section is for contributors and developers wanting to build, test, and contribute to mcp-cpp-sdk itself.
To build the library, tests, and examples locally:
# Install dependencies
python scripts/init.py
# Build project (release with examples and tests)
python scripts/build.py --examples --test| Flag | Description |
|---|---|
--debug |
Build in debug mode |
--test |
Build and run unit tests |
--examples |
Build example applications |
--conformance |
Build fixtures for the official MCP conformance runner |
--linkage {both,shared,static} |
Select which SDK linkage variants to build |
--cppstd {20,23} |
Select the C++ consumer standard (default: C++20) |
--sanitize |
Build with ASan/UBSan (Linux/macOS) |
--docs |
Generate local Doxygen + Sphinx documentation |
--clean |
Clean build artifacts |
- Formatting:
make format(requiresclang-format) - Linting:
make lint(requiresclang-tidy) - Testing: We use GoogleTest for all unit and integration tests.
Please see the CONTRIBUTING guide for the full process.
Project maintenance commitments and release gates are documented in the maintenance policy, dependency policy, versioning policy, Tier roadmap, and security policy.
Apache License 2.0 - see LICENSE for details.
Package repository hosting is graciously provided by Cloudsmith. Cloudsmith is the only fully hosted, cloud-native, universal package management solution that enables your organization to create, store and share packages in any format, to any place, with total confidence.