Cookbook

Copy-paste recipes for common tasks.

Short, focused code snippets. Each recipe solves one problem. See Tutorials for full walkthroughs.

Server

Minimal stdio server (one-liner)

The shortest possible MCP server.

#include <cxxmcp/peer.hpp>
#include <cxxmcp/run.hpp>

int main() {
    return mcp::ServerPeer::builder()
        .name("minimal").version("1.0.0").stdio()
        .tool<mcp::protocol::Json, mcp::protocol::Json>(
            "echo", [](const mcp::protocol::Json& in) { return in; })
        .run();
}

HTTP server

Serve over Streamable HTTP. Requires CXXMCP_ENABLE_HTTP=ON.

auto server = mcp::ServerPeer::builder()
    .name("http-server").version("1.0.0")
    .streamable_http("127.0.0.1", 3000, "/mcp")
    .tool<Json, Json>("echo", [](const Json& in) { return in; })
    .build();

auto running = mcp::serve(std::move(*server));
running->wait_until_ready();
running->wait();

Add a typed tool with reflection

Auto-serialize args and results with CXXMCP_REFLECT.

struct Args { std::string query; int limit; };
struct Result { std::vector<std::string> items; };

CXXMCP_REFLECT(Args, query, limit)
CXXMCP_REFLECT(Result, items)
// In builder:
.tool(mcp::server::tool<Args, Result>("search")
          .description("Search items.")
          .handler([](Args args, const mcp::server::ToolContext&) {
              Result r;
              for (int i = 0; i < args.limit; ++i)
                  r.items.push_back(args.query + "_" + std::to_string(i));
              return r;
          }))

Add a prompt

.prompt(mcp::protocol::Prompt{
            .name = "summarize",
            .description = "Summarize text",
            .arguments = {mcp::protocol::PromptArgument{
                .name = "text", .required = true,
            }},
        },
        [](const mcp::server::PromptContext& ctx) {
            auto text = ctx.arguments.at("text").get<std::string>();
            mcp::protocol::PromptsGetResult result;
            result.messages.push_back(mcp::protocol::PromptMessage{
                .role = "user",
                .content = mcp::protocol::ContentBlock{
                    .type = "text", .text = "Summarize: " + text},
            });
            return result;
        })

Add a static resource

.resource("file:///data/config.json", [] {
    return mcp::protocol::ResourceContents{
        .uri = "file:///data/config.json",
        .mime_type = "application/json",
        .text = R"({"version": 1})",
    };
})

Add a resource template

.resource_template("file:///workspace/{path}", [] {
    return mcp::protocol::ResourceTemplate{
        .uri_template = "file:///workspace/{path}",
        .name = "Workspace files",
    };
})

Handle raw JSON-RPC requests

For custom methods or vendor extensions.

.raw_request([](const mcp::protocol::JsonRpcRequest& req)
                 -> std::optional<mcp::protocol::JsonRpcResponse> {
    if (req.method == "myapp/health") {
        return mcp::protocol::make_response(
            req.id, mcp::protocol::Json{{"ok", true}});
    }
    return std::nullopt;  // unhandled, let SDK return method-not-found
})

Client

Connect to a stdio server

return mcp::ClientPeer::builder()
    .process_stdio("./my-server")
    .run([](auto& svc) {
        svc.peer().initialize();
        auto result = svc.peer().call_tool(
            "echo", Json{{"value", "hello"}});
    });

Connect to an HTTP server

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();

List all tools

auto tools = svc.peer().list_all_tools();
for (const auto& tool : tools) {
    std::cout << tool.name << ": " << tool.description << "\n";
}

Read a resource

auto contents = svc.peer().read_resource("file:///data/config.json");
for (const auto& c : *contents) {
    std::cout << c.text << "\n";
}

Get a prompt

mcp::protocol::Json args{{"text", "The quick brown fox."}};
auto result = svc.peer().get_prompt("summarize", args);

Auth

Bearer token server + client

// Server
auto auth = std::make_unique<mcp::server::StaticBearerAuthProvider>();
auth->add_token("my-token", mcp::server::AuthIdentity{"alice", {}});

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<Json, Json>("whoami", [](const Json&, const auto& ctx) {
        return Json{{"subject",
            ctx.auth_identity ? ctx.auth_identity->subject : "anon"}};
    })
    .build();

// Client
auto client = mcp::ClientPeer::builder()
    .streamable_http("http://127.0.0.1:3001/mcp")
    .bearer_token("my-token")
    .build();

CMake flags for auth

# Auth contracts only (no OpenSSL)
cmake -S . -B build -DCXXMCP_ENABLE_AUTH=ON

# With OpenSSL crypto (DPoP, JWT, JWKS)
cmake -S . -B build -DCXXMCP_ENABLE_AUTH=ON -DCXXMCP_AUTH_CRYPTO=OpenSSL

# vcpkg
vcpkg install "cxxmcp-sdk[auth]"

Tasks and Async

Task-aware tool

.task_manager(mcp::server::TaskOperationProcessorOptions{
    .worker_count = 2, .queue_size = 16,
})
.tool(mcp::server::tool<Json, Json>("heavy")
          .task_support(mcp::protocol::TaskSupport::Optional)
          .handler([](const Json& args, const auto& ctx) {
              // runs in background task
              return Json{{"done", true}};
          }))

Request timeout

// Client-side timeout
auto result = svc.peer().call_tool(
    "slow-tool", Json{{"data", "x"}},
    std::chrono::seconds(30));

Cancel a task

auto task = svc.peer().call_tool("heavy", Json{{}});
svc.peer().cancel_task(task->task_id);

CMake

Minimum CMakeLists.txt

cmake_minimum_required(VERSION 3.16)
project(my-app LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)

find_package(cxxmcp CONFIG REQUIRED)
add_executable(server server.cpp)
target_link_libraries(server PRIVATE cxxmcp::server)

All CMake options

cmake -S . -B build \
  -DCXXMCP_BUILD_SDK=ON \           # aggregate SDK (default ON)
  -DCXXMCP_BUILD_CLIENT=ON \        # client library
  -DCXXMCP_BUILD_SERVER=ON \        # server library
  -DCXXMCP_BUILD_EXAMPLES=ON \      # example executables
  -DCXXMCP_BUILD_TESTS=ON \         # tests
  -DCXXMCP_ENABLE_HTTP=ON \         # HTTP transport (cpp-httplib)
  -DCXXMCP_ENABLE_AUTH=ON \         # OAuth 2.1 / DPoP contracts
  -DCXXMCP_AUTH_CRYPTO=OpenSSL      # OpenSSL crypto backend

FetchContent consumption

include(FetchContent)
FetchContent_Declare(cxxmcp
    URL https://github.com/caomengxuan666/cxxmcp/releases/download/v1.1.6/cxxmcp-sdk-source-v1.1.6.tar.gz
    URL_HASH SHA256=7d321ee1e48f71666659949c98b5e3c81b273db98607b21d7b3d9301f5bf42e2
)
FetchContent_MakeAvailable(cxxmcp)

target_link_libraries(my_app PRIVATE cxxmcp::server)

Next Steps