Transports

Move JSON-RPC messages between client and server.

cxxmcp ships four built-in transports and lets you implement custom ones. This page covers each transport's API, options, and behavior.

Transport Overview

TransportRoleCMake FlagBuilder MethodClass
stdioServer + Clientdefault.stdio()StdioTransport
Process stdioClientdefault.process_stdio(cmd)ProcessStdioClientTransport
Streamable HTTPServer + ClientCXXMCP_ENABLE_HTTP.streamable_http(...)StreamableHttp{Server,Client}Transport
WebSocketServer + ClientCXXMCP_ENABLE_HTTP + CXXMCP_ENABLE_WEBSOCKET.websocket(...)WebSocket{Server,Client}Transport
CustomEitherimplement Transport<Role>your class

stdio Transport

Reads JSON-RPC messages from stdin, writes responses to stdout. The simplest transport — ideal for CLI tools, local subprocess integrations, and editors that launch MCP servers as child processes.

Server

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

int main() {
    return mcp::ServerPeer::builder()
        .name("my-server").version("1.0.0")
        .stdio()                          // enables stdio transport
        .tool<Json, Json>("echo", handler)
        .run();
}

Client

// Launch a server process and talk to it via stdin/stdout
auto client = mcp::ClientPeer::builder()
    .process_stdio("./my-server")        // launches the process
    .build();

Behavior

  • One JSON-RPC message per line (newline-delimited JSON)
  • Server blocks until stdin is closed or stop() is called
  • No multiplexing — one request at a time
  • No network overhead — fastest transport for local use

Process stdio Transport

Client-only transport that launches a server as a subprocess and communicates over its stdin/stdout. The process lifecycle is managed by the transport.

Usage

// Simple command
auto client = mcp::ClientPeer::builder()
    .process_stdio("node my-server.js")
    .build();

// With arguments
auto client = mcp::ClientPeer::builder()
    .process_stdio("python -m my_mcp_server --port stdio")
    .build();

// With options
mcp::transport::ProcessStdioClientTransportOptions opts;
opts.command = "./my-server";
opts.working_directory = "/path/to/server";
auto client = mcp::ClientPeer::builder()
    .process_stdio(opts)
    .build();

Behavior

  • Process is started on first send() or initialize()
  • Process is terminated when the transport is destroyed or close() is called
  • Response ID validation ensures responses match requests
  • Timeout on process startup (configurable)

Streamable HTTP Transport

Full-duplex HTTP transport with SSE streaming. Supports stateful sessions, concurrent requests, and server-to-client notifications. Requires CXXMCP_ENABLE_HTTP=ON.

Build

cmake -S . -B build -DCXXMCP_ENABLE_HTTP=ON -DCXXMCP_BUILD_SERVER=ON -DCXXMCP_BUILD_CLIENT=ON

Server

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

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

Server Options

mcp::transport::StreamableHttpServerTransportOptions opts;
opts.listen_host = "0.0.0.0";         // Bind address
opts.listen_port = 8080;               // Port
opts.path = "/mcp";                    // Endpoint path
opts.session_header = "Mcp-Session-Id"; // Session header name

auto server = mcp::ServerPeer::builder()
    .name("my-server").version("1.0.0")
    .streamable_http(opts)
    .build();

Client

auto client = mcp::ClientPeer::builder()
    .streamable_http("http://127.0.0.1:3000/mcp")
    .build();

// With bearer token
auto client = mcp::ClientPeer::builder()
    .streamable_http("http://127.0.0.1:3000/mcp")
    .bearer_token("my-secret-token")
    .build();

Client Options

mcp::transport::StreamableHttpClientTransportOptions opts;
opts.base_url = "http://127.0.0.1:3000/mcp";
opts.timeout = std::chrono::seconds(30);
opts.bearer_token = "my-secret-token";

auto client = mcp::ClientPeer::builder()
    .streamable_http(opts)
    .build();

Behavior

  • POST requests carry JSON-RPC messages; responses may be SSE streams
  • GET opens an SSE channel for server-to-client notifications
  • DELETE terminates the session
  • Session state is tracked via Mcp-Session-Id header
  • SEP-2243: Mcp-Method and Mcp-Name headers are validated when present (optional for backward compat)
  • Legacy SSE endpoint /sse is supported for older clients

WebSocket Transport

Full-duplex message transport over WebSocket with client reconnect support. Requires CXXMCP_ENABLE_HTTP=ON and CXXMCP_ENABLE_WEBSOCKET=ON.

Build

cmake -S . -B build -DCXXMCP_ENABLE_HTTP=ON -DCXXMCP_ENABLE_WEBSOCKET=ON -DCXXMCP_BUILD_SERVER=ON -DCXXMCP_BUILD_CLIENT=ON

Server

auto server = mcp::ServerPeer::builder()
    .name("ws-server").version("1.0.0")
    .websocket(3001)
    .tool<Json, Json>("echo", [](const Json& in) { return in; })
    .build();

Client

auto client = mcp::ClientPeer::builder()
    .websocket("ws://127.0.0.1:3001/mcp")
    .build();

Custom Transports

Implement the Transport<Role> interface to create your own transport (Unix socket, in-memory loopback, shared memory, etc.).

#include <cxxmcp/transport/transport.hpp>

// Client transport
class MyClientTransport : public mcp::transport::ClientTransport {
 public:
    mcp::core::Result<mcp::protocol::JsonRpcResponse> send(
        const mcp::protocol::JsonRpcRequest& request) override {
        // Serialize request, send over your channel, return response
    }

    mcp::core::Result<mcp::core::Unit> send_notification(
        const mcp::protocol::JsonRpcNotification& notification) override {
        // Send notification (no response expected)
    }
};

// Server transport
class MyServerTransport : public mcp::transport::ServerTransport {
 public:
    void on_request(RequestHandler handler) override {
        // Store handler; call it when a request arrives on your channel
    }

    mcp::core::Result<mcp::core::Unit> send_response(
        const mcp::protocol::JsonRpcResponse& response) override {
        // Send response back to client
    }
};

Built-in Adapters

The SDK provides adapter classes for common patterns:

  • FunctionTransport<Role> — wrap lambda functions as a transport
  • JsonLineTransport<Role> — newline-delimited JSON over any stream
  • QueueTransport<Role> — in-memory queue for testing

Next Steps