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

Transport | Role | CMake Flag | Builder Method | Class
--- | --- | --- | --- | ---
stdio | Server + Client | default | `.stdio()` | `StdioTransport`
Process stdio | Client | default | `.process_stdio(cmd)` | `ProcessStdioClientTransport`
Streamable HTTP | Server + Client | `CXXMCP_ENABLE_HTTP` | `.streamable_http(...)` | `StreamableHttp{Server,Client}Transport`
WebSocket | Server + Client | `CXXMCP_ENABLE_HTTP` + `CXXMCP_ENABLE_WEBSOCKET` | `.websocket(...)` | `WebSocket{Server,Client}Transport`
Custom | Either | — | implement `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

- Auth — secure your HTTP transport
- Tutorials — build with each transport
- API Reference — full transport class docs