Troubleshooting

# Common issues and how to fix them.

Solutions for build errors, runtime problems, and integration issues.

## Build Errors

### CMake cannot find cxxmcp

Error: `Could not find a package configuration file provided by "cxxmcp"`

Solution: Install the SDK first, or use FetchContent:

    # Option 1: Install then consume
    cmake --install build --prefix /path/to/install
    cmake -S myapp -B build -DCMAKE_PREFIX_PATH=/path/to/install

    # Option 2: FetchContent (no install needed)
    include(FetchContent)
    FetchContent_Declare(cxxmcp URL https://github.com/caomengxuan666/cxxmcp/releases/download/v1.1.6/cxxmcp-sdk-source-v1.1.6.tar.gz)
    FetchContent_MakeAvailable(cxxmcp)

### HTTP transport symbols not found

Error: `undefined reference to mcp::transport::StreamableHttpServerTransport`

Solution: HTTP transport is off by default. Enable it:

    cmake -S . -B build -DCXXMCP_ENABLE_HTTP=ON

### Auth target not found

Error: `Target "cxxmcp::auth" not found`

Solution: Auth is opt-in:

    cmake -S . -B build -DCXXMCP_ENABLE_AUTH=ON

    # With OpenSSL DPoP/JWKS support
    cmake -S . -B build -DCXXMCP_ENABLE_AUTH=ON -DCXXMCP_AUTH_CRYPTO=OpenSSL

### OpenSSL not found

Error: `Could not find a package configuration file provided by "OpenSSL"`

Solution: Tell CMake where OpenSSL is:

    # Windows (vcpkg)
    cmake -S . -B build -DCMAKE_TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake

    # Linux (system package)
    sudo apt install libssl-dev
    cmake -S . -B build

    # Manual path
    cmake -S . -B build -DOPENSSL_ROOT_DIR=/path/to/openssl

### C++17 compiler errors

Error: `error: 'optional' is not a member of 'std'`

Solution: Ensure C++17 is enabled:

    set(CMAKE_CXX_STANDARD 17)
    set(CMAKE_CXX_STANDARD_REQUIRED ON)

### vcpkg cannot find cxxmcp

Error: `error: Unable to find package cxxmcp-sdk`

Solution: Use the overlay port from the repository:

    vcpkg install cxxmcp-sdk --overlay-ports=path/to/cxxmcp/packaging/vcpkg/ports

## Runtime Issues

### Server does not respond to tools/list

Symptom: Client sends `tools/list` but gets method-not-found.

Solution: You must register at least one tool with the builder. An empty server has no tools capability:

    auto server = mcp::ServerPeer::builder()
        .name("my-server").version("1.0.0").stdio()
        .tool<Json, Json>("echo", handler)  // This enables the tools capability
        .build();

### HTTP server connection refused

Symptom: Client gets `connection refused` on HTTP.

Solution: Call `wait_until_ready()` before connecting:

    auto running = mcp::serve(std::move(*server));
    running->wait_until_ready();  // Wait for socket to bind
    // Now safe to connect clients

### Bearer token rejected

Symptom: Server returns `401 Unauthorized`.

Solution: Ensure the auth provider is set before building:

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

    auto server = mcp::ServerPeer::builder()
        .name("my-server").version("1.0.0")
        .auth_provider(std::move(auth))  // Must be before .build()
        .streamable_http(...)
        .build();

### Tool handler not called

Symptom: `tools/call` returns method-not-found.

Solution: Tool name in `call_tool()` must match the registered name exactly (case-sensitive):

    // Registration
    .tool<Json, Json>("my_tool", handler)

    // Call — must match exactly
    svc.peer().call_tool("my_tool", Json{{}});  // OK
    svc.peer().call_tool("My_Tool", Json{{}});  // FAILS

### Process stdio server exits immediately

Symptom: Client launches server process but it exits right away.

Solution: The server must block on `wait()`:

    auto running = mcp::serve(std::move(*server));
    running->wait();  // Blocks until stdin closes or shutdown

## Reflection and Serialization

### CXXMCP_REFLECT compilation error

Error: `no matching function for call to 'Reflect'`

Solution: Place the macro at namespace scope. Global scope is the usual choice:

    struct MyType { std::string name; int value; };

    CXXMCP_REFLECT(MyType, name, value)

### JSON deserialization returns empty fields

Symptom: Fields are default-initialized after `reflect_from_json`.

Solution: JSON keys must match the C++ field names exactly:

    // C++ field: std::string query;
    // JSON must have: {"query": "value"}
    // NOT: {"q": "value"}

### Optional field not serialized

Symptom: `std::optional<T>` field is missing from output JSON.

Behavior: This is correct. Empty optionals are omitted from JSON output. They deserialize as `std::nullopt` when the key is absent.

## Conformance Testing

### Conformance runner not found

Solution: The runner is a separate tool. See modelcontextprotocol/conformance:

    git clone https://github.com/modelcontextprotocol/conformance.git
    cd conformance
    npm install
    npm run build
    node dist/cli.js --suite all --server-command "path/to/your/server"

### Server conformance: 109/110

Result: 109 of 110 server tests pass. All 448 client tests pass.

Note: The remaining server exception is the SEP-2243 missing-method-header case described in conformance evidence.

## Still Stuck?

- GitHub Issues — search for existing issues or file a new one
- Discussions — ask questions and share ideas
- API Reference — generated symbol documentation