From cdb489aea2c6983a94fcd215cd455c56713d351d Mon Sep 17 00:00:00 2001 From: Elias Bachaalany Date: Fri, 5 Dec 2025 19:47:19 -0800 Subject: [PATCH 1/2] Fix StreamableHttpTransport to build JSON-RPC envelope and extract result The StreamableHttpTransport::request method was passing the params directly to the server instead of wrapping them in a JSON-RPC envelope. It was also returning the full JSON-RPC response instead of extracting the result. Fixes: - Build proper JSON-RPC request with jsonrpc, method, params, and id - Extract result from JSON-RPC response envelope - Handle JSON-RPC errors by throwing TransportError --- src/client/transports.cpp | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/src/client/transports.cpp b/src/client/transports.cpp index 3e6aba0..87c618d 100644 --- a/src/client/transports.cpp +++ b/src/client/transports.cpp @@ -924,7 +924,7 @@ fastmcpp::Json StreamableHttpTransport::parse_response(const std::string& body, } } -fastmcpp::Json StreamableHttpTransport::request(const std::string& /*route*/, +fastmcpp::Json StreamableHttpTransport::request(const std::string& route, const fastmcpp::Json& payload) { auto url = parse_url(base_url_); @@ -951,11 +951,13 @@ fastmcpp::Json StreamableHttpTransport::request(const std::string& /*route*/, request_headers.emplace("Mcp-Session-Id", session_id_); } - // Payload is the full JSON-RPC request - // (StreamableHttp transport accepts complete JSON-RPC requests, unlike other transports) + // Build JSON-RPC request (route is method, payload is params) + int64_t id = next_id_.fetch_add(1, std::memory_order_relaxed); + fastmcpp::Json rpc_request = { + {"jsonrpc", "2.0"}, {"method", route}, {"params", payload}, {"id", id}}; // Send request - auto res = cli.Post(mcp_path_.c_str(), request_headers, payload.dump(), "application/json"); + auto res = cli.Post(mcp_path_.c_str(), request_headers, rpc_request.dump(), "application/json"); if (!res) throw fastmcpp::TransportError("StreamableHttp request failed: no response"); @@ -982,8 +984,20 @@ fastmcpp::Json StreamableHttpTransport::request(const std::string& /*route*/, // Parse response auto rpc_response = parse_response(res->body, content_type); - // Return full JSON-RPC response (caller handles error/result extraction) - return rpc_response; + // Check for JSON-RPC error + if (rpc_response.contains("error")) + { + auto error = rpc_response["error"]; + std::string message = error.value("message", "Unknown error"); + throw fastmcpp::TransportError("JSON-RPC error: " + message); + } + + // Extract result from JSON-RPC envelope + if (rpc_response.contains("result")) + return rpc_response["result"]; + + // If no result or error, return empty object + return fastmcpp::Json::object(); } } // namespace fastmcpp::client From c53b71590b961ddcd6d03ac53ecca82d844911eb Mon Sep 17 00:00:00 2001 From: Elias Bachaalany Date: Fri, 5 Dec 2025 20:09:47 -0800 Subject: [PATCH 2/2] Fix clang-format for streaming_demo.cpp and sse.cpp --- examples/streaming_demo.cpp | 3 ++- tests/server/sse.cpp | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/examples/streaming_demo.cpp b/examples/streaming_demo.cpp index f9ee26b..559abf8 100644 --- a/examples/streaming_demo.cpp +++ b/examples/streaming_demo.cpp @@ -48,7 +48,8 @@ int main() std::thread sse_thread( [&, port]() { - // Create client inside thread - httplib::Client is not thread-safe across threads on Linux + // Create client inside thread - httplib::Client is not thread-safe across threads on + // Linux httplib::Client cli("127.0.0.1", port); cli.set_connection_timeout(std::chrono::seconds(10)); cli.set_read_timeout(std::chrono::seconds(20)); diff --git a/tests/server/sse.cpp b/tests/server/sse.cpp index ea2148f..661fed7 100644 --- a/tests/server/sse.cpp +++ b/tests/server/sse.cpp @@ -66,7 +66,8 @@ int main() std::thread sse_thread( [&, port]() { - // Create client inside thread - httplib::Client is not thread-safe across threads on Linux + // Create client inside thread - httplib::Client is not thread-safe across threads on + // Linux httplib::Client sse_client("127.0.0.1", port); sse_client.set_read_timeout(std::chrono::seconds(20)); sse_client.set_connection_timeout(std::chrono::seconds(10));