vcpkg overlay
Use the repository-hosted overlay port until cxxmcp is accepted into a curated registry.
# Clone the repo first, then:
vcpkg install cxxmcp-sdk \
--overlay-ports=packaging/vcpkg/ports
Start with the public package targets, keep external tooling outside the SDK package path, and use Peer/Service as the first-choice SDK boundary for new code.
A source checkout can install the SDK targets into a local prefix. The SDK headers and public package targets are C++17-compatible.
cmake -S . -B build -DCXXMCP_BUILD_SDK=ON -DCXXMCP_BUILD_CLIENT=ON -DCXXMCP_BUILD_SERVER=ON
cmake --build build --config Release
cmake --install build --config Release --prefix out/install/cxxmcp
Downstream projects should link the narrowest target they need.
Use cxxmcp::sdk only when one binary intentionally needs
protocol, client, and server APIs together.
find_package(cxxmcp CONFIG REQUIRED)
add_executable(my_server server.cpp)
target_link_libraries(my_server PRIVATE cxxmcp::server)
add_executable(my_client client.cpp)
target_link_libraries(my_client PRIVATE cxxmcp::client)
Register server capabilities with the server builder, wrap the built
server in mcp::ServerPeer, add a transport, and serve it.
#include <iostream>
#include <memory>
#include <utility>
#include <cxxmcp/peer.hpp>
#include <cxxmcp/server.hpp>
#include <cxxmcp/service.hpp>
#include <cxxmcp/transport/stdio_transport.hpp>
int main() {
mcp::server::ServerBuilder builder;
builder.name("demo-server")
.version("1.0.0")
.add_tool(
mcp::protocol::ToolDefinition{
.name = "echo",
.description = "Echo the incoming payload",
.input_schema = mcp::protocol::Json{{"type", "object"}},
},
[](const mcp::server::ToolContext& context) {
mcp::protocol::ToolResult result;
result.structured_content = context.arguments;
return result;
});
auto server = builder.build();
if (!server) {
return 1;
}
mcp::ServerPeer peer(std::move(*server));
peer.add_transport(
std::make_unique<mcp::transport::ServerStdioTransport>(
std::cin, std::cout));
auto running = mcp::serve(std::move(peer));
if (!running) {
return 1;
}
return running->wait().has_value() ? 0 : 1;
}
HTTP transport requires CXXMCP_ENABLE_HTTP=ON at build
time. The SDK bundles cpp-httplib as a header-only
dependency.
# Build with HTTP transport
cmake -S . -B build -DCXXMCP_ENABLE_HTTP=ON -DCXXMCP_BUILD_SERVER=ON -DCXXMCP_BUILD_CLIENT=ON
Server and client builder both expose
.streamable_http(...):
// Server — listen on HTTP
auto server = mcp::ServerPeer::builder()
.name("my-server")
.version("1.0.0")
.streamable_http("127.0.0.1", 3000, "/mcp") // host, port, path
.tool(mcp::server::tool<Json, Json>("echo")
.handler([](const Json& in) { return in; }))
.build();
auto running = mcp::serve(std::move(*server));
running->wait_until_ready();
// Client — connect over HTTP
auto client = mcp::ClientPeer::builder()
.streamable_http("http://127.0.0.1:3000/mcp")
.build();
auto svc = mcp::serve(std::move(*client));
svc->peer().initialize();
svc->peer().call_tool("echo", Json{{"value", "hello"}});
Auth is opt-in. Set CXXMCP_ENABLE_AUTH=ON to export
cxxmcp::auth with PKCE, DPoP, metadata endpoints, and
bearer-token helpers.
# Auth contracts (no OpenSSL)
cmake -S . -B build -DCXXMCP_ENABLE_AUTH=ON
# With OpenSSL crypto backend
cmake -S . -B build -DCXXMCP_ENABLE_AUTH=ON -DCXXMCP_AUTH_CRYPTO=OpenSSL
vcpkg shortcut: vcpkg install "cxxmcp-sdk[auth]".
Add a bearer-token auth provider to the server builder:
#include <cxxmcp/peer.hpp>
auto auth = std::make_unique<mcp::server::StaticBearerAuthProvider>();
auth->add_token("my-secret",
mcp::server::AuthIdentity{
"alice", {{"scope", "tools:call"}},
});
auto server = mcp::ServerPeer::builder()
.name("auth-demo")
.version("1.0.0")
.auth_provider(std::move(auth))
.streamable_http("127.0.0.1", 3001, "/mcp")
.tool(mcp::server::tool<Json, Json>("whoami")
.handler([](const Json&, const mcp::server::ToolContext& ctx) {
return Json{{"subject",
ctx.auth_identity ? ctx.auth_identity->subject : "anon"}};
}))
.build();
Client side — pass the bearer token:
auto client = mcp::ClientPeer::builder()
.streamable_http("http://127.0.0.1:3001/mcp")
.bearer_token("my-secret")
.build();
When CXXMCP_AUTH_CRYPTO=OpenSSL is set alongside
CXXMCP_ENABLE_AUTH=ON, the SDK resolves OpenSSL via
find_package(OpenSSL) and exports
cxxmcp::auth_openssl. This enables:
StaticJwksDpopBearerAuthProviderFetchingJwksJwtVerifier for remote JWKS#include <cxxmcp/auth/openssl/server_auth_provider.hpp>
mcp::auth::DpopAuthProviderOptions opts;
opts.require_dpop = true;
opts.issuer = "https://auth.example.com";
opts.audience = "https://resource.example/mcp";
auto auth =
std::make_unique<mcp::auth::openssl::StaticJwksDpopBearerAuthProvider>(
std::move(jwks), &replay_cache, opts);
OpenSSL is not vendored — it must be available on the system
or through a package manager. Set OPENSSL_ROOT_DIR if
CMake cannot find it automatically.
The CXXMCP_REFLECT macro gives your structs automatic
JSON serialization, deserialization, and JSON Schema generation — no
boilerplate.
#include <cxxmcp/protocol/reflect.hpp>
struct SearchArgs {
std::string query;
int limit = 3;
};
struct SearchResult {
std::string session;
std::vector<SearchHit> hits;
};
CXXMCP_REFLECT(SearchArgs, query, limit)
CXXMCP_REFLECT(SearchResult, session, hits)
Once reflected, use typed tool registration:
.tool(mcp::server::tool<SearchArgs, SearchResult>("search")
.description("Search local documents.")
.handler([](SearchArgs args, const mcp::server::ToolContext& ctx) {
SearchResult result;
result.session = ctx.session_id;
// ...
return result;
}))
The SDK auto-generates inputSchema from
SearchArgs fields and serializes
SearchResult back to JSON. Use
CXXMCP_REFLECT_CHECK(Type, N) to validate field count at
compile time.
schema_for<T>() returns a
nlohmann::json JSON Schema object for any reflected or
primitive type.
Use the repository-hosted overlay port until cxxmcp is accepted into a curated registry.
# Clone the repo first, then:
vcpkg install cxxmcp-sdk \
--overlay-ports=packaging/vcpkg/ports
Prefer the SDK source release archive because it carries the bundled header-only SDK dependencies used by default builds.