From 9b71eedc9a5179aa1c12a42542f07f373c2f8f72 Mon Sep 17 00:00:00 2001 From: gophergogo Date: Sun, 5 Oct 2025 15:39:44 -0700 Subject: [PATCH 01/33] Change RequestId and ProgressToken to use int64_t instead of int (#121) JSON-RPC allows string or number for request IDs. Using int64_t instead of int prevents overflow when generating numeric request IDs from uint64_t counters. Changes: - Update RequestId type from variant to variant - Update ProgressToken type to use int64_t for consistency - Add factory function for int64_t request IDs - Update all usages of holds_alternative to holds_alternative - Update all usages of get to get for RequestId/ProgressToken - Change pending_requests_ map key from int to int64_t in RequestTracker - Cast uint64_t request ID counters to int64_t to avoid overflow --- include/mcp/client/mcp_client.h | 12 ++-- include/mcp/filter/metrics_filter.h | 2 +- include/mcp/server/mcp_server.h | 2 +- include/mcp/types.h | 10 ++- src/client/mcp_client.cc | 4 +- src/echo/echo_client_advanced.cc | 4 +- src/filter/http_sse_filter_chain_factory.cc | 8 +-- src/json/json_serialization.cc | 32 ++++----- src/server/mcp_server.cc | 6 +- tests/core/test_mcp_type_helpers.cc | 8 +-- tests/core/test_mcp_types.cc | 72 +++++++++---------- tests/filter/test_json_rpc_protocol_filter.cc | 10 +-- tests/network/test_mcp_connection_manager.cc | 16 ++--- tests/transport/test_stdio_echo_client.cc | 8 +-- tests/transport/test_stdio_echo_server.cc | 8 +-- tests/transport/test_stdio_pipe_bridge.cc | 12 ++-- 16 files changed, 109 insertions(+), 105 deletions(-) diff --git a/include/mcp/client/mcp_client.h b/include/mcp/client/mcp_client.h index 56c662ca..d47d58ff 100644 --- a/include/mcp/client/mcp_client.h +++ b/include/mcp/client/mcp_client.h @@ -293,15 +293,15 @@ class RequestTracker { // Add request to tracking void trackRequest(RequestPtr request) { std::lock_guard lock(mutex_); - // Extract int ID from RequestId - int id = holds_alternative(request->id) ? get(request->id) : 0; + // Extract int64_t ID from RequestId + int64_t id = holds_alternative(request->id) ? get(request->id) : 0; pending_requests_[id] = request; } // Get request by ID without removing RequestPtr getRequest(const RequestId& id) { std::lock_guard lock(mutex_); - int int_id = holds_alternative(id) ? get(id) : 0; + int64_t int_id = holds_alternative(id) ? get(id) : 0; auto it = pending_requests_.find(int_id); if (it != pending_requests_.end()) { return it->second; @@ -312,7 +312,7 @@ class RequestTracker { // Remove and return request RequestPtr removeRequest(const RequestId& id) { std::lock_guard lock(mutex_); - int int_id = holds_alternative(id) ? get(id) : 0; + int64_t int_id = holds_alternative(id) ? get(id) : 0; auto it = pending_requests_.find(int_id); if (it != pending_requests_.end()) { auto request = it->second; @@ -336,7 +336,7 @@ class RequestTracker { // Remove timed out requests from tracking for (const auto& request : timed_out) { - int id = holds_alternative(request->id) ? get(request->id) : 0; + int64_t id = holds_alternative(request->id) ? get(request->id) : 0; pending_requests_.erase(id); } @@ -352,7 +352,7 @@ class RequestTracker { mutable std::mutex mutex_; std::chrono::milliseconds timeout_; // Store using int ID extracted from RequestId - std::unordered_map pending_requests_; + std::unordered_map pending_requests_; }; /** diff --git a/include/mcp/filter/metrics_filter.h b/include/mcp/filter/metrics_filter.h index 2957046b..6eca07da 100644 --- a/include/mcp/filter/metrics_filter.h +++ b/include/mcp/filter/metrics_filter.h @@ -232,7 +232,7 @@ class MetricsFilter : public network::NetworkFilterBase, } // Start tracking request latency - if (holds_alternative(request.id) || + if (holds_alternative(request.id) || holds_alternative(request.id)) { std::lock_guard lock(request_mutex_); pending_requests_[requestIdToString(request.id)] = diff --git a/include/mcp/server/mcp_server.h b/include/mcp/server/mcp_server.h index 80fed9e3..566f1b91 100644 --- a/include/mcp/server/mcp_server.h +++ b/include/mcp/server/mcp_server.h @@ -694,7 +694,7 @@ class McpServer : public application::ApplicationBase, // Convert RequestId to string key std::string key = holds_alternative(id) ? get(id) - : std::to_string(get(id)); + : std::to_string(get(id)); auto it = pending_requests_.find(key); return (it != pending_requests_.end() && it->second->cancelled.load()); } diff --git a/include/mcp/types.h b/include/mcp/types.h index 3cd42861..708ac9ae 100644 --- a/include/mcp/types.h +++ b/include/mcp/types.h @@ -32,8 +32,10 @@ constexpr int INTERNAL_ERROR = -32603; } // namespace jsonrpc // Protocol type aliases -using RequestId = variant; -using ProgressToken = variant; +// JSON-RPC allows string or number for request IDs and progress tokens +// Using int64_t to support large numeric IDs without overflow +using RequestId = variant; +using ProgressToken = variant; using Cursor = std::string; // Enum definitions @@ -148,7 +150,9 @@ inline RequestId make_request_id(const std::string& id) { return RequestId(id); } -inline RequestId make_request_id(int id) { return RequestId(id); } +inline RequestId make_request_id(int id) { return RequestId(static_cast(id)); } + +inline RequestId make_request_id(int64_t id) { return RequestId(id); } inline RequestId make_request_id(const char* id) { return RequestId(std::string(id)); diff --git a/src/client/mcp_client.cc b/src/client/mcp_client.cc index dea0896c..9b6b9887 100644 --- a/src/client/mcp_client.cc +++ b/src/client/mcp_client.cc @@ -409,7 +409,7 @@ std::future McpClient::sendRequest(const std::string& method, } // Generate request ID - RequestId id = next_request_id_++; + RequestId id = static_cast(next_request_id_++); // Create request context auto context = std::make_shared(id, method); @@ -983,7 +983,7 @@ std::future McpClient::createMessage( // to use messages and preferences parameters directly // Send request - RequestId id = next_request_id_++; + RequestId id = static_cast(next_request_id_++); auto context = std::make_shared(id, "messages/create"); context->params = make_optional(params); context->start_time = std::chrono::steady_clock::now(); diff --git a/src/echo/echo_client_advanced.cc b/src/echo/echo_client_advanced.cc index d37c3651..760f8795 100644 --- a/src/echo/echo_client_advanced.cc +++ b/src/echo/echo_client_advanced.cc @@ -348,8 +348,8 @@ void AdvancedEchoClient::processMessage(const std::string& message) { // Response auto response = json::from_json(json_val); - if (holds_alternative(response.id)) { - int id = get(response.id); + if (holds_alternative(response.id)) { + int id = get(response.id); auto request = request_manager_->getRequest(id); if (request) { diff --git a/src/filter/http_sse_filter_chain_factory.cc b/src/filter/http_sse_filter_chain_factory.cc index e6a487a9..1d3efb81 100644 --- a/src/filter/http_sse_filter_chain_factory.cc +++ b/src/filter/http_sse_filter_chain_factory.cc @@ -90,10 +90,10 @@ class HttpSseJsonRpcProtocolFilter; // Utility function to convert RequestId to string for logging static std::string requestIdToString(const RequestId& id) { - if (id.holds_alternative()) { - return id.get(); - } else if (id.holds_alternative()) { - return std::to_string(id.get()); + if (holds_alternative(id)) { + return get(id); + } else if (holds_alternative(id)) { + return std::to_string(get(id)); } return ""; } diff --git a/src/json/json_serialization.cc b/src/json/json_serialization.cc index a1716455..770a7fa6 100644 --- a/src/json/json_serialization.cc +++ b/src/json/json_serialization.cc @@ -789,7 +789,7 @@ JsonValue serialize_InitializeRequest(const InitializeRequest& request) { // Add base class ID if present if ((mcp::holds_alternative(request.id) && !mcp::get(request.id).empty()) || - mcp::holds_alternative(request.id)) { + mcp::holds_alternative(request.id)) { builder.add("id", to_json(request.id)); } @@ -807,7 +807,7 @@ JsonValue serialize_PingRequest(const PingRequest& request) { // Add base class ID if present if ((mcp::holds_alternative(request.id) && !mcp::get(request.id).empty()) || - mcp::holds_alternative(request.id)) { + mcp::holds_alternative(request.id)) { builder.add("id", to_json(request.id)); } @@ -820,7 +820,7 @@ JsonValue serialize_CompleteRequest(const CompleteRequest& request) { // Add base class ID if present if ((mcp::holds_alternative(request.id) && !mcp::get(request.id).empty()) || - mcp::holds_alternative(request.id)) { + mcp::holds_alternative(request.id)) { builder.add("id", to_json(request.id)); } @@ -837,7 +837,7 @@ JsonValue serialize_SetLevelRequest(const SetLevelRequest& request) { // Add base class ID if present if ((mcp::holds_alternative(request.id) && !mcp::get(request.id).empty()) || - mcp::holds_alternative(request.id)) { + mcp::holds_alternative(request.id)) { builder.add("id", to_json(request.id)); } @@ -852,7 +852,7 @@ JsonValue serialize_CallToolRequest(const CallToolRequest& request) { // Add base class ID if present if ((mcp::holds_alternative(request.id) && !mcp::get(request.id).empty()) || - mcp::holds_alternative(request.id)) { + mcp::holds_alternative(request.id)) { builder.add("id", to_json(request.id)); } @@ -871,7 +871,7 @@ JsonValue serialize_ListToolsRequest(const ListToolsRequest& request) { // Add base class ID if present if ((mcp::holds_alternative(request.id) && !mcp::get(request.id).empty()) || - mcp::holds_alternative(request.id)) { + mcp::holds_alternative(request.id)) { builder.add("id", to_json(request.id)); } @@ -916,7 +916,7 @@ JsonValue serialize_GetPromptRequest(const GetPromptRequest& request) { // Add base class ID if present if ((mcp::holds_alternative(request.id) && !mcp::get(request.id).empty()) || - mcp::holds_alternative(request.id)) { + mcp::holds_alternative(request.id)) { builder.add("id", to_json(request.id)); } @@ -935,7 +935,7 @@ JsonValue serialize_ListPromptsRequest(const ListPromptsRequest& request) { // Add base class ID if present if ((mcp::holds_alternative(request.id) && !mcp::get(request.id).empty()) || - mcp::holds_alternative(request.id)) { + mcp::holds_alternative(request.id)) { builder.add("id", to_json(request.id)); } @@ -968,7 +968,7 @@ JsonValue serialize_ReadResourceRequest(const ReadResourceRequest& request) { // Add base class ID if present if ((mcp::holds_alternative(request.id) && !mcp::get(request.id).empty()) || - mcp::holds_alternative(request.id)) { + mcp::holds_alternative(request.id)) { builder.add("id", to_json(request.id)); } @@ -982,7 +982,7 @@ JsonValue serialize_ListResourcesRequest(const ListResourcesRequest& request) { // Add base class ID if present if ((mcp::holds_alternative(request.id) && !mcp::get(request.id).empty()) || - mcp::holds_alternative(request.id)) { + mcp::holds_alternative(request.id)) { builder.add("id", to_json(request.id)); } @@ -999,7 +999,7 @@ JsonValue serialize_ListResourceTemplatesRequest( // Add base class ID if present if ((mcp::holds_alternative(request.id) && !mcp::get(request.id).empty()) || - mcp::holds_alternative(request.id)) { + mcp::holds_alternative(request.id)) { builder.add("id", to_json(request.id)); } @@ -1015,7 +1015,7 @@ JsonValue serialize_SubscribeRequest(const SubscribeRequest& request) { // Add base class ID if present if ((mcp::holds_alternative(request.id) && !mcp::get(request.id).empty()) || - mcp::holds_alternative(request.id)) { + mcp::holds_alternative(request.id)) { builder.add("id", to_json(request.id)); } @@ -1029,7 +1029,7 @@ JsonValue serialize_UnsubscribeRequest(const UnsubscribeRequest& request) { // Add base class ID if present if ((mcp::holds_alternative(request.id) && !mcp::get(request.id).empty()) || - mcp::holds_alternative(request.id)) { + mcp::holds_alternative(request.id)) { builder.add("id", to_json(request.id)); } @@ -1055,7 +1055,7 @@ JsonValue serialize_ListRootsRequest(const ListRootsRequest& request) { // Add base class ID if present if ((mcp::holds_alternative(request.id) && !mcp::get(request.id).empty()) || - mcp::holds_alternative(request.id)) { + mcp::holds_alternative(request.id)) { builder.add("id", to_json(request.id)); } @@ -1069,7 +1069,7 @@ JsonValue serialize_CreateMessageRequest(const CreateMessageRequest& request) { // Add base class ID if present if ((mcp::holds_alternative(request.id) && !mcp::get(request.id).empty()) || - mcp::holds_alternative(request.id)) { + mcp::holds_alternative(request.id)) { builder.add("id", to_json(request.id)); } @@ -1121,7 +1121,7 @@ JsonValue serialize_ElicitRequest(const ElicitRequest& request) { // Add base class ID if present if ((mcp::holds_alternative(request.id) && !mcp::get(request.id).empty()) || - mcp::holds_alternative(request.id)) { + mcp::holds_alternative(request.id)) { builder.add("id", to_json(request.id)); } diff --git a/src/server/mcp_server.cc b/src/server/mcp_server.cc index 8861800b..1736367f 100644 --- a/src/server/mcp_server.cc +++ b/src/server/mcp_server.cc @@ -475,7 +475,7 @@ void McpServer::onRequest(const jsonrpc::Request& request) { // Convert RequestId to string key std::string key = holds_alternative(request.id) ? get(request.id) - : std::to_string(get(request.id)); + : std::to_string(get(request.id)); pending_requests_[key] = pending_req; } @@ -576,7 +576,7 @@ void McpServer::onRequest(const jsonrpc::Request& request) { std::cerr << "[DEBUG] Sending response for request id: " << (holds_alternative(request.id) ? get(request.id) - : std::to_string(get(request.id))) + : std::to_string(get(request.id))) << std::endl; // Send response through the current connection (for TCP/HTTP connections) @@ -609,7 +609,7 @@ void McpServer::onRequest(const jsonrpc::Request& request) { // Convert RequestId to string key std::string key = holds_alternative(request.id) ? get(request.id) - : std::to_string(get(request.id)); + : std::to_string(get(request.id)); pending_requests_.erase(key); } } diff --git a/tests/core/test_mcp_type_helpers.cc b/tests/core/test_mcp_type_helpers.cc index e8953290..8844bfe4 100644 --- a/tests/core/test_mcp_type_helpers.cc +++ b/tests/core/test_mcp_type_helpers.cc @@ -802,8 +802,8 @@ TEST_F(MCPTypeHelpersTest, RequestIdFactories) { // Integer ID auto id2 = make_request_id(42); - EXPECT_TRUE(mcp::holds_alternative(id2)); - EXPECT_EQ(mcp::get(id2), 42); + EXPECT_TRUE(mcp::holds_alternative(id2)); + EXPECT_EQ(mcp::get(id2), 42); // C-string ID (should convert to std::string) auto id3 = make_request_id("req-456"); @@ -817,7 +817,7 @@ TEST_F(MCPTypeHelpersTest, ProgressTokenFactories) { EXPECT_TRUE(mcp::holds_alternative(token1)); auto token2 = make_progress_token(100); - EXPECT_TRUE(mcp::holds_alternative(token2)); + EXPECT_TRUE(mcp::holds_alternative(token2)); } // Test ContentBlock factories @@ -941,7 +941,7 @@ TEST_F(MCPTypeHelpersTest, JSONRPCFactories) { // Test request creation auto req1 = make_request(make_request_id(1), "initialize"); EXPECT_EQ(req1.jsonrpc, "2.0"); - EXPECT_TRUE(mcp::holds_alternative(req1.id)); + EXPECT_TRUE(mcp::holds_alternative(req1.id)); EXPECT_EQ(req1.method, "initialize"); EXPECT_FALSE(req1.params.has_value()); diff --git a/tests/core/test_mcp_types.cc b/tests/core/test_mcp_types.cc index 26a751dd..f49fffd8 100644 --- a/tests/core/test_mcp_types.cc +++ b/tests/core/test_mcp_types.cc @@ -349,13 +349,13 @@ TEST_F(MCPTypesTest, RequestIdTypeAlias) { // Test int variant RequestId intId = 456; - EXPECT_TRUE(mcp::holds_alternative(intId)); - EXPECT_EQ(mcp::get(intId), 456); + EXPECT_TRUE(mcp::holds_alternative(intId)); + EXPECT_EQ(mcp::get(intId), 456); // Test assignment stringId = 789; - EXPECT_TRUE(mcp::holds_alternative(stringId)); - EXPECT_EQ(mcp::get(stringId), 789); + EXPECT_TRUE(mcp::holds_alternative(stringId)); + EXPECT_EQ(mcp::get(stringId), 789); } TEST_F(MCPTypesTest, ProgressTokenTypeAlias) { @@ -366,8 +366,8 @@ TEST_F(MCPTypesTest, ProgressTokenTypeAlias) { // Test int variant ProgressToken intToken = 999; - EXPECT_TRUE(mcp::holds_alternative(intToken)); - EXPECT_EQ(mcp::get(intToken), 999); + EXPECT_TRUE(mcp::holds_alternative(intToken)); + EXPECT_EQ(mcp::get(intToken), 999); } TEST_F(MCPTypesTest, CursorTypeAlias) { @@ -393,8 +393,8 @@ TEST_F(MCPTypesTest, RequestIdFactoriesExtensive) { // Test int factory auto id3 = make_request_id(12345); - EXPECT_TRUE(mcp::holds_alternative(id3)); - EXPECT_EQ(mcp::get(id3), 12345); + EXPECT_TRUE(mcp::holds_alternative(id3)); + EXPECT_EQ(mcp::get(id3), 12345); // Test with empty string auto id4 = make_request_id(""); @@ -403,13 +403,13 @@ TEST_F(MCPTypesTest, RequestIdFactoriesExtensive) { // Test with negative int auto id5 = make_request_id(-1); - EXPECT_TRUE(mcp::holds_alternative(id5)); - EXPECT_EQ(mcp::get(id5), -1); + EXPECT_TRUE(mcp::holds_alternative(id5)); + EXPECT_EQ(mcp::get(id5), -1); // Test with max int auto id6 = make_request_id(std::numeric_limits::max()); - EXPECT_TRUE(mcp::holds_alternative(id6)); - EXPECT_EQ(mcp::get(id6), std::numeric_limits::max()); + EXPECT_TRUE(mcp::holds_alternative(id6)); + EXPECT_EQ(mcp::get(id6), std::numeric_limits::max()); } // Extensive tests for ProgressToken factory functions @@ -426,8 +426,8 @@ TEST_F(MCPTypesTest, ProgressTokenFactoriesExtensive) { // Test int factory auto token3 = make_progress_token(54321); - EXPECT_TRUE(mcp::holds_alternative(token3)); - EXPECT_EQ(mcp::get(token3), 54321); + EXPECT_TRUE(mcp::holds_alternative(token3)); + EXPECT_EQ(mcp::get(token3), 54321); // Test with special characters in string auto token4 = make_progress_token("token-with-special-!@#$%^&*()"); @@ -436,8 +436,8 @@ TEST_F(MCPTypesTest, ProgressTokenFactoriesExtensive) { // Test with zero auto token5 = make_progress_token(0); - EXPECT_TRUE(mcp::holds_alternative(token5)); - EXPECT_EQ(mcp::get(token5), 0); + EXPECT_TRUE(mcp::holds_alternative(token5)); + EXPECT_EQ(mcp::get(token5), 0); } // Extensive tests for Role enum @@ -548,8 +548,8 @@ TEST_F(MCPTypesTest, MakeMethodRequestExtensive) { // Test with int RequestId auto req2 = make_method_request(make_request_id(456), "another/method", 42); - EXPECT_TRUE(mcp::holds_alternative(req2.first)); - EXPECT_EQ(mcp::get(req2.first), 456); + EXPECT_TRUE(mcp::holds_alternative(req2.first)); + EXPECT_EQ(mcp::get(req2.first), 456); EXPECT_EQ(req2.second.method, "another/method"); EXPECT_TRUE(req2.second.is_type()); @@ -844,8 +844,8 @@ TEST_F(MCPTypesTest, ProtocolTypeAliases) { // RequestId - int variant RequestId id2 = 42; - EXPECT_TRUE(mcp::holds_alternative(id2)); - EXPECT_EQ(mcp::get(id2), 42); + EXPECT_TRUE(mcp::holds_alternative(id2)); + EXPECT_EQ(mcp::get(id2), 42); // ProgressToken - string variant ProgressToken token1 = std::string("progress-abc"); @@ -854,8 +854,8 @@ TEST_F(MCPTypesTest, ProtocolTypeAliases) { // ProgressToken - int variant ProgressToken token2 = 99; - EXPECT_TRUE(mcp::holds_alternative(token2)); - EXPECT_EQ(mcp::get(token2), 99); + EXPECT_TRUE(mcp::holds_alternative(token2)); + EXPECT_EQ(mcp::get(token2), 99); // Cursor (simple string alias) Cursor cursor = "cursor-token-xyz"; @@ -950,8 +950,8 @@ TEST_F(MCPTypesTest, RequestIdFactoriesComprehensive) { // Test int overload auto id2 = make_request_id(42); - EXPECT_TRUE(mcp::holds_alternative(id2)); - EXPECT_EQ(mcp::get(id2), 42); + EXPECT_TRUE(mcp::holds_alternative(id2)); + EXPECT_EQ(mcp::get(id2), 42); // Test const char* overload auto id3 = make_request_id("literal-456"); @@ -964,12 +964,12 @@ TEST_F(MCPTypesTest, RequestIdFactoriesComprehensive) { EXPECT_EQ(mcp::get(id4), ""); auto id5 = make_request_id(0); // Zero - EXPECT_TRUE(mcp::holds_alternative(id5)); - EXPECT_EQ(mcp::get(id5), 0); + EXPECT_TRUE(mcp::holds_alternative(id5)); + EXPECT_EQ(mcp::get(id5), 0); auto id6 = make_request_id(-1); // Negative - EXPECT_TRUE(mcp::holds_alternative(id6)); - EXPECT_EQ(mcp::get(id6), -1); + EXPECT_TRUE(mcp::holds_alternative(id6)); + EXPECT_EQ(mcp::get(id6), -1); } // Test ProgressToken factory functions comprehensively @@ -981,8 +981,8 @@ TEST_F(MCPTypesTest, ProgressTokenFactoriesComprehensive) { // Test int overload auto token2 = make_progress_token(100); - EXPECT_TRUE(mcp::holds_alternative(token2)); - EXPECT_EQ(mcp::get(token2), 100); + EXPECT_TRUE(mcp::holds_alternative(token2)); + EXPECT_EQ(mcp::get(token2), 100); // Test const char* overload auto token3 = make_progress_token("literal-token"); @@ -995,8 +995,8 @@ TEST_F(MCPTypesTest, ProgressTokenFactoriesComprehensive) { EXPECT_EQ(mcp::get(token4), ""); auto token5 = make_progress_token(0); // Zero - EXPECT_TRUE(mcp::holds_alternative(token5)); - EXPECT_EQ(mcp::get(token5), 0); + EXPECT_TRUE(mcp::holds_alternative(token5)); + EXPECT_EQ(mcp::get(token5), 0); } // Test make_method_request function @@ -1335,17 +1335,17 @@ TEST_F(MCPTypesTest, EdgeCasesAndBoundaryValues) { // Zero and negative numbers auto zero_id = make_request_id(0); - EXPECT_EQ(mcp::get(zero_id), 0); + EXPECT_EQ(mcp::get(zero_id), 0); auto negative_id = make_request_id(-999); - EXPECT_EQ(mcp::get(negative_id), -999); + EXPECT_EQ(mcp::get(negative_id), -999); // Maximum/minimum values auto max_int_id = make_request_id(std::numeric_limits::max()); - EXPECT_EQ(mcp::get(max_int_id), std::numeric_limits::max()); + EXPECT_EQ(mcp::get(max_int_id), std::numeric_limits::max()); auto min_int_id = make_request_id(std::numeric_limits::min()); - EXPECT_EQ(mcp::get(min_int_id), std::numeric_limits::min()); + EXPECT_EQ(mcp::get(min_int_id), std::numeric_limits::min()); // Error with data - using simplified ErrorData type Error error_with_data(400, "Bad request"); diff --git a/tests/filter/test_json_rpc_protocol_filter.cc b/tests/filter/test_json_rpc_protocol_filter.cc index 966bac7a..21fbf819 100644 --- a/tests/filter/test_json_rpc_protocol_filter.cc +++ b/tests/filter/test_json_rpc_protocol_filter.cc @@ -92,8 +92,8 @@ TEST_F(JsonRpcProtocolFilterTest, ParseRequest) { EXPECT_CALL(*callbacks_, onRequest(_)) .WillOnce([](const jsonrpc::Request& req) { EXPECT_EQ("test.method", req.method); - EXPECT_TRUE(holds_alternative(req.id)); - EXPECT_EQ(1, get(req.id)); + EXPECT_TRUE(holds_alternative(req.id)); + EXPECT_EQ(1, get(req.id)); }); // Create JSON-RPC request @@ -137,8 +137,8 @@ TEST_F(JsonRpcProtocolFilterTest, ParseResponse) { // Expect onResponse to be called EXPECT_CALL(*callbacks_, onResponse(_)) .WillOnce([](const jsonrpc::Response& resp) { - EXPECT_TRUE(holds_alternative(resp.id)); - EXPECT_EQ(42, get(resp.id)); + EXPECT_TRUE(holds_alternative(resp.id)); + EXPECT_EQ(42, get(resp.id)); EXPECT_TRUE(resp.result.has_value()); }); @@ -414,7 +414,7 @@ TEST_F(JsonRpcProtocolFilterIntegrationTest, EndToEndMessageFlow) { EXPECT_CALL(*server_callbacks_, onRequest(_)) .WillOnce([](const jsonrpc::Request& req) { EXPECT_EQ("test.method", req.method); - EXPECT_EQ(123, get(req.id)); + EXPECT_EQ(123, get(req.id)); }); // Send request from client diff --git a/tests/network/test_mcp_connection_manager.cc b/tests/network/test_mcp_connection_manager.cc index 41312820..89eb8060 100644 --- a/tests/network/test_mcp_connection_manager.cc +++ b/tests/network/test_mcp_connection_manager.cc @@ -87,8 +87,8 @@ R"({"jsonrpc":"2.0","id":123,"method":"test_method","params":{"key":"value"}})"; // Verify callback EXPECT_EQ(1, callbacks_.request_called_); - EXPECT_TRUE(mcp::holds_alternative(callbacks_.last_request_.id)); - EXPECT_EQ(123, mcp::get(callbacks_.last_request_.id)); + EXPECT_TRUE(mcp::holds_alternative(callbacks_.last_request_.id)); + EXPECT_EQ(123, mcp::get(callbacks_.last_request_.id)); EXPECT_EQ("test_method", callbacks_.last_request_.method); EXPECT_TRUE(callbacks_.last_request_.params.has_value()); } @@ -127,8 +127,8 @@ R"({"jsonrpc":"2.0","id":456,"result":{"status":"ok"}})"; // Verify callback EXPECT_EQ(1, callbacks_.response_called_); - EXPECT_TRUE(mcp::holds_alternative(callbacks_.last_response_.id)); - EXPECT_EQ(456, mcp::get(callbacks_.last_response_.id)); + EXPECT_TRUE(mcp::holds_alternative(callbacks_.last_response_.id)); + EXPECT_EQ(456, mcp::get(callbacks_.last_response_.id)); EXPECT_TRUE(callbacks_.last_response_.result.has_value()); EXPECT_FALSE(callbacks_.last_response_.error.has_value()); } @@ -149,8 +149,8 @@ found","data":"test_method"}})"; // Verify callback EXPECT_EQ(1, callbacks_.response_called_); - EXPECT_TRUE(mcp::holds_alternative(callbacks_.last_response_.id)); - EXPECT_EQ(789, mcp::get(callbacks_.last_response_.id)); + EXPECT_TRUE(mcp::holds_alternative(callbacks_.last_response_.id)); + EXPECT_EQ(789, mcp::get(callbacks_.last_response_.id)); EXPECT_FALSE(callbacks_.last_response_.result.has_value()); EXPECT_TRUE(callbacks_.last_response_.error.has_value()); EXPECT_EQ(-32601, callbacks_.last_response_.error->code); @@ -408,8 +408,8 @@ TEST_F(McpConnectionManagerTest, MessageCallbackForwarding) { manager_->onResponse(response); EXPECT_EQ(1, callbacks_.response_called_); - EXPECT_TRUE(mcp::holds_alternative(callbacks_.last_response_.id)); - EXPECT_EQ(2, mcp::get(callbacks_.last_response_.id)); + EXPECT_TRUE(mcp::holds_alternative(callbacks_.last_response_.id)); + EXPECT_EQ(2, mcp::get(callbacks_.last_response_.id)); // Simulate error Error error; diff --git a/tests/transport/test_stdio_echo_client.cc b/tests/transport/test_stdio_echo_client.cc index b6f22623..5af75101 100644 --- a/tests/transport/test_stdio_echo_client.cc +++ b/tests/transport/test_stdio_echo_client.cc @@ -214,8 +214,8 @@ class StdioEchoClientTest : public ::testing::Test { received_responses_.push_back(response); // Check pending request - if (holds_alternative(response.id)) { - int id = get(response.id); + if (holds_alternative(response.id)) { + int id = get(response.id); auto it = pending_requests_.find(id); if (it != pending_requests_.end()) { completed_requests_[id] = it->second; @@ -469,8 +469,8 @@ TEST_F(StdioEchoClientTest, RequestResponse) { EXPECT_EQ(1, client.getCompletedRequests().size()); auto& response = client.getReceivedResponses()[0]; - EXPECT_TRUE(holds_alternative(response.id)); - EXPECT_EQ(request_id, get(response.id)); + EXPECT_TRUE(holds_alternative(response.id)); + EXPECT_EQ(request_id, get(response.id)); client.stop(); } diff --git a/tests/transport/test_stdio_echo_server.cc b/tests/transport/test_stdio_echo_server.cc index d7780084..e97e2d78 100644 --- a/tests/transport/test_stdio_echo_server.cc +++ b/tests/transport/test_stdio_echo_server.cc @@ -364,8 +364,8 @@ TEST_F(StdioEchoServerTest, DISABLED_RequestEcho) { jsonrpc::Response parsed_response = json::from_json(response_json); - EXPECT_TRUE(holds_alternative(parsed_response.id)); - EXPECT_EQ(1, get(parsed_response.id)); + EXPECT_TRUE(holds_alternative(parsed_response.id)); + EXPECT_EQ(1, get(parsed_response.id)); EXPECT_TRUE(parsed_response.result.has_value()); server.stop(); @@ -467,8 +467,8 @@ TEST_F(StdioEchoServerTest, DISABLED_MultipleRequests) { auto response_json = json::JsonValue::parse(responses[i]); jsonrpc::Response parsed = json::from_json(response_json); - EXPECT_TRUE(holds_alternative(parsed.id)); - EXPECT_EQ(static_cast(i + 1), get(parsed.id)); + EXPECT_TRUE(holds_alternative(parsed.id)); + EXPECT_EQ(static_cast(i + 1), get(parsed.id)); } server.stop(); diff --git a/tests/transport/test_stdio_pipe_bridge.cc b/tests/transport/test_stdio_pipe_bridge.cc index e86c27c6..cf413f97 100644 --- a/tests/transport/test_stdio_pipe_bridge.cc +++ b/tests/transport/test_stdio_pipe_bridge.cc @@ -502,8 +502,8 @@ TEST_F(StdioPipeBridgeTest, JsonRpcMessageFlow) { jsonrpc::Response parsed_response = json::from_json(response_json); - EXPECT_TRUE(holds_alternative(parsed_response.id)); - EXPECT_EQ(1, get(parsed_response.id)); + EXPECT_TRUE(holds_alternative(parsed_response.id)); + EXPECT_EQ(1, get(parsed_response.id)); EXPECT_TRUE(parsed_response.result.has_value()); EXPECT_FALSE(parsed_response.error.has_value()); } @@ -719,8 +719,8 @@ class MockBridgeClient : public McpProtocolCallbacks { received_responses_.push_back(response); // Check pending request - if (holds_alternative(response.id)) { - int id = get(response.id); + if (holds_alternative(response.id)) { + int id = get(response.id); auto it = pending_requests_.find(id); if (it != pending_requests_.end()) { completed_requests_[id] = it->second; @@ -1090,8 +1090,8 @@ TEST_F(StdioPipeBridgeTest, MultipleSequentialRequests) { auto response_json = json::JsonValue::parse(responses[i]); jsonrpc::Response parsed = json::from_json(response_json); - EXPECT_TRUE(holds_alternative(parsed.id)); - EXPECT_EQ(static_cast(i + 1), get(parsed.id)); + EXPECT_TRUE(holds_alternative(parsed.id)); + EXPECT_EQ(static_cast(i + 1), get(parsed.id)); } server.stop(); } From 600eca566546074527dfa0bbb208e4072cfd01da Mon Sep 17 00:00:00 2001 From: gophergogo Date: Sun, 5 Oct 2025 15:42:37 -0700 Subject: [PATCH 02/33] Fix constructor initialization order warning in Logger class (#122) The compiler warned that member 'mode_' was being initialized before 'effective_level_' despite appearing later in the initializer list. Reordered the initializer list to match the member declaration order in the class (effective_level_, name_, mode_) to eliminate the warning. This follows C++ best practice where initialization order follows declaration order, not initializer list order. --- include/mcp/logging/logger.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/mcp/logging/logger.h b/include/mcp/logging/logger.h index a4773c66..7b731e35 100644 --- a/include/mcp/logging/logger.h +++ b/include/mcp/logging/logger.h @@ -19,7 +19,7 @@ namespace logging { class Logger : public std::enable_shared_from_this { public: explicit Logger(const std::string& name, LogMode mode = LogMode::Async) - : name_(name), mode_(mode), effective_level_(LogLevel::Info) { + : effective_level_(LogLevel::Info), name_(name), mode_(mode) { // Temporarily disable async mode to fix hanging tests if (mode == LogMode::Async) { mode_ = LogMode::Sync; // Force sync mode for now From bb74b90c05025d073cb7969c294b7114ec13c7f5 Mon Sep 17 00:00:00 2001 From: gophergogo Date: Sun, 5 Oct 2025 15:43:08 -0700 Subject: [PATCH 03/33] Add virtual destructor to ConnectionStateMachine class (#122) The compiler warned about deleting a non-final class with virtual functions through a base pointer without a virtual destructor. Made the destructor virtual to ensure proper cleanup when ConnectionStateMachine is used polymorphically. This fixes the warning: 'delete called on non-final ConnectionStateMachine that has virtual functions but non-virtual destructor' --- include/mcp/network/connection_state_machine.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/mcp/network/connection_state_machine.h b/include/mcp/network/connection_state_machine.h index 51a715ff..91a16b5e 100644 --- a/include/mcp/network/connection_state_machine.h +++ b/include/mcp/network/connection_state_machine.h @@ -291,7 +291,7 @@ class ConnectionStateMachine { ConnectionStateMachine(event::Dispatcher& dispatcher, const ConnectionStateMachineConfig& config); - ~ConnectionStateMachine(); + virtual ~ConnectionStateMachine(); // ===== Core State Machine Interface ===== From c7caf0f77fef618f0043b9b7fca999775977a2a0 Mon Sep 17 00:00:00 2001 From: gophergogo Date: Sun, 5 Oct 2025 15:43:53 -0700 Subject: [PATCH 04/33] Fix C++17 compatibility by using std functions directly (#120) When using C++17 std::optional and std::variant, import the std functions directly into mcp namespace using 'using' declarations instead of creating wrapper template functions. This avoids ambiguous function call errors between std:: and mcp:: versions. Changes: - Replace make_optional wrapper templates with 'using std::make_optional' - Replace get/get_if/holds_alternative/visit wrapper templates with 'using std::*' declarations - Keeps wrapper implementations only for C++14 compatibility path This eliminates ambiguity errors like: 'call to make_optional is ambiguous' 'call to holds_alternative is ambiguous' 'call to get is ambiguous' --- include/mcp/core/compat.h | 94 +++------------------------------------ 1 file changed, 7 insertions(+), 87 deletions(-) diff --git a/include/mcp/core/compat.h b/include/mcp/core/compat.h index 808f2ccc..cbdc77ad 100644 --- a/include/mcp/core/compat.h +++ b/include/mcp/core/compat.h @@ -48,22 +48,8 @@ inline constexpr auto in_place = std::in_place; using bad_optional_access = std::bad_optional_access; -// make_optional helpers -template -constexpr optional::type> make_optional(T&& value) { - return std::make_optional(std::forward(value)); -} - -template -constexpr optional make_optional(Args&&... args) { - return std::make_optional(std::forward(args)...); -} - -template -constexpr optional make_optional(std::initializer_list il, - Args&&... args) { - return std::make_optional(il, std::forward(args)...); -} +// Import std functions into mcp namespace +using std::make_optional; #else // Use mcp:: implementations (already defined in optional.h) // Just need to ensure they're in the mcp namespace @@ -75,77 +61,11 @@ using variant = std::variant; using bad_variant_access = std::bad_variant_access; -template -constexpr T* get_if(variant* v) noexcept { - return std::get_if(v); -} - -template -constexpr const T* get_if(const variant* v) noexcept { - return std::get_if(v); -} - -template -constexpr T& get(variant& v) { - return std::get(v); -} - -template -constexpr const T& get(const variant& v) { - return std::get(v); -} - -template -constexpr T&& get(variant&& v) { - return std::get(std::move(v)); -} - -template -constexpr const T&& get(const variant&& v) { - return std::get(std::move(v)); -} - -template -constexpr bool holds_alternative(const variant& v) noexcept { - return std::holds_alternative(v); -} - -template -constexpr decltype(auto) visit(Visitor&& vis, Variants&&... vars) { - return std::visit(std::forward(vis), - std::forward(vars)...); -} - -// Helper for index-based operations -template -constexpr auto& get(variant& v) { - return std::get(v); -} - -template -constexpr const auto& get(const variant& v) { - return std::get(v); -} - -template -constexpr auto&& get(variant&& v) { - return std::get(std::move(v)); -} - -template -constexpr const auto&& get(const variant&& v) { - return std::get(std::move(v)); -} - -template -constexpr auto* get_if(variant* v) noexcept { - return std::get_if(v); -} - -template -constexpr const auto* get_if(const variant* v) noexcept { - return std::get_if(v); -} +// Import std functions into mcp namespace for ADL +using std::get; +using std::get_if; +using std::holds_alternative; +using std::visit; #else // Use mcp:: implementations and provide std-like free functions From 4065d8013ca24f94336e1182561c0fad3a0019bf Mon Sep 17 00:00:00 2001 From: gophergogo Date: Sun, 5 Oct 2025 15:44:42 -0700 Subject: [PATCH 05/33] Add missing string header to io_result.h (#122) SystemError struct uses std::string but the header was missing. This caused compilation errors about implicit instantiation of undefined template 'std::basic_string' when io_result.h was included before any header that transitively included . Added explicit #include to fix the dependency. --- include/mcp/io_result.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/mcp/io_result.h b/include/mcp/io_result.h index 96e6c51e..a1179cee 100644 --- a/include/mcp/io_result.h +++ b/include/mcp/io_result.h @@ -3,6 +3,7 @@ #include #include +#include #ifdef _WIN32 #include From 47173d031fdffc9a082fe73cda84a06e198f3768 Mon Sep 17 00:00:00 2001 From: gophergogo Date: Sun, 5 Oct 2025 15:45:14 -0700 Subject: [PATCH 06/33] Add make_overload helper function for variant visitation (#120) Added make_overload() factory function that creates an overload object from a set of lambda functions. This provides a cleaner syntax for std::visit with multiple visitor lambdas. The helper forwards arguments to construct the overload pattern and enables usage like: visit(make_overload( [](Type1) { ... }, [](Type2) { ... } ), variant_obj); This was being used in metrics_filter.h but was not defined, causing compilation errors. --- include/mcp/core/type_helpers.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/mcp/core/type_helpers.h b/include/mcp/core/type_helpers.h index 404f4de1..64f3f395 100644 --- a/include/mcp/core/type_helpers.h +++ b/include/mcp/core/type_helpers.h @@ -277,6 +277,11 @@ struct overload : Fs... { template overload(Fs...) -> overload; +template +constexpr auto make_overload(Fs&&... fs) { + return overload{std::forward(fs)...}; +} + template auto match(Variant&& v, Visitors&&... visitors) { return std::visit(overload{std::forward(visitors)...}, From 3b97c6b642d990c50250b3524d5034d4687ab9e3 Mon Sep 17 00:00:00 2001 From: gophergogo Date: Sun, 5 Oct 2025 15:46:18 -0700 Subject: [PATCH 07/33] Use compat.h instead of direct optional.h include (#120) Changed stdio_pipe_transport.h to include mcp/core/compat.h instead of mcp/core/optional.h directly. This ensures proper selection between std::optional (C++17) and mcp::optional (C++14) based on the compiler version. Direct inclusion of optional.h caused conflicts when C++17 was enabled, as both std::optional and mcp::optional definitions would be present. The compat.h header provides the correct abstraction layer. --- include/mcp/transport/stdio_pipe_transport.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/mcp/transport/stdio_pipe_transport.h b/include/mcp/transport/stdio_pipe_transport.h index e0a44e97..3b0e803e 100644 --- a/include/mcp/transport/stdio_pipe_transport.h +++ b/include/mcp/transport/stdio_pipe_transport.h @@ -5,7 +5,7 @@ #include #include "mcp/buffer.h" -#include "mcp/core/optional.h" +#include "mcp/core/compat.h" #include "mcp/network/io_handle.h" #include "mcp/network/socket.h" #include "mcp/network/socket_impl.h" From ea9b89040c16076a12b869f9f9ed25f5f813edf8 Mon Sep 17 00:00:00 2001 From: gophergogo Date: Sun, 5 Oct 2025 16:13:55 -0700 Subject: [PATCH 08/33] Change RequestId and ProgressToken to use int64_t instead of int -- miss-out fixes (#121) --- include/mcp/echo/echo_basic.h | 4 ++-- tests/filter/test_http_sse_filter_chain_factory.cc | 4 ++-- tests/filter/test_json_rpc_filter_factory.cc | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/include/mcp/echo/echo_basic.h b/include/mcp/echo/echo_basic.h index dd8350d5..91a9b57f 100644 --- a/include/mcp/echo/echo_basic.h +++ b/include/mcp/echo/echo_basic.h @@ -651,8 +651,8 @@ class EchoClientBase { std::lock_guard lock(pending_mutex_); int id = 0; - if (holds_alternative(response.id)) { - id = get(response.id); + if (holds_alternative(response.id)) { + id = get(response.id); } auto it = pending_requests_.find(id); diff --git a/tests/filter/test_http_sse_filter_chain_factory.cc b/tests/filter/test_http_sse_filter_chain_factory.cc index f93977bf..4982694f 100644 --- a/tests/filter/test_http_sse_filter_chain_factory.cc +++ b/tests/filter/test_http_sse_filter_chain_factory.cc @@ -282,7 +282,7 @@ TEST_F(HttpSseFilterChainFactoryTest, DISABLED_ProcessHttpRequest) { EXPECT_CALL(*message_callbacks_, onRequest(_)) .WillOnce([](const jsonrpc::Request& req) { EXPECT_EQ("initialize", req.method); - EXPECT_EQ(1, get(req.id)); + EXPECT_EQ(1, get(req.id)); }); // Send the HTTP request through the filter chain @@ -331,7 +331,7 @@ TEST_F(HttpSseFilterChainFactoryTest, DISABLED_ProcessSseEvents) { // We expect the JSON-RPC response to be parsed from SSE event EXPECT_CALL(*message_callbacks_, onResponse(_)) .WillOnce([](const jsonrpc::Response& resp) { - EXPECT_EQ(1, get(resp.id)); + EXPECT_EQ(1, get(resp.id)); EXPECT_TRUE(resp.result.has_value()); }); diff --git a/tests/filter/test_json_rpc_filter_factory.cc b/tests/filter/test_json_rpc_filter_factory.cc index 3ef30fa2..7fa62ae2 100644 --- a/tests/filter/test_json_rpc_filter_factory.cc +++ b/tests/filter/test_json_rpc_filter_factory.cc @@ -142,7 +142,7 @@ TEST_F(JsonRpcFilterChainFactoryTest, DirectCallbacksAdapter) { EXPECT_CALL(*message_callbacks_, onRequest(_)) .WillOnce([](const jsonrpc::Request& req) { EXPECT_EQ("test.method", req.method); - EXPECT_EQ(123, get(req.id)); + EXPECT_EQ(123, get(req.id)); }); adapter.onRequest(request); @@ -167,7 +167,7 @@ TEST_F(JsonRpcFilterChainFactoryTest, DirectCallbacksAdapter) { EXPECT_CALL(*message_callbacks_, onResponse(_)) .WillOnce([](const jsonrpc::Response& resp) { - EXPECT_EQ(456, get(resp.id)); + EXPECT_EQ(456, get(resp.id)); }); adapter.onResponse(response); From 18e944bfb7050bd8040d05e440d327230e2a8535 Mon Sep 17 00:00:00 2001 From: gophergogo Date: Sun, 5 Oct 2025 16:28:16 -0700 Subject: [PATCH 09/33] make format CPP code to apply clang-format (#122) --- include/mcp/client/mcp_client.h | 7 +++++-- include/mcp/types.h | 4 +++- src/c_api/mcp_c_filter_api.cc | 22 ++++++++++++---------- 3 files changed, 20 insertions(+), 13 deletions(-) diff --git a/include/mcp/client/mcp_client.h b/include/mcp/client/mcp_client.h index d47d58ff..b3adb0c8 100644 --- a/include/mcp/client/mcp_client.h +++ b/include/mcp/client/mcp_client.h @@ -294,7 +294,8 @@ class RequestTracker { void trackRequest(RequestPtr request) { std::lock_guard lock(mutex_); // Extract int64_t ID from RequestId - int64_t id = holds_alternative(request->id) ? get(request->id) : 0; + int64_t id = + holds_alternative(request->id) ? get(request->id) : 0; pending_requests_[id] = request; } @@ -336,7 +337,9 @@ class RequestTracker { // Remove timed out requests from tracking for (const auto& request : timed_out) { - int64_t id = holds_alternative(request->id) ? get(request->id) : 0; + int64_t id = holds_alternative(request->id) + ? get(request->id) + : 0; pending_requests_.erase(id); } diff --git a/include/mcp/types.h b/include/mcp/types.h index 708ac9ae..2aa6af49 100644 --- a/include/mcp/types.h +++ b/include/mcp/types.h @@ -150,7 +150,9 @@ inline RequestId make_request_id(const std::string& id) { return RequestId(id); } -inline RequestId make_request_id(int id) { return RequestId(static_cast(id)); } +inline RequestId make_request_id(int id) { + return RequestId(static_cast(id)); +} inline RequestId make_request_id(int64_t id) { return RequestId(id); } diff --git a/src/c_api/mcp_c_filter_api.cc b/src/c_api/mcp_c_filter_api.cc index 00534b24..c79b87dd 100644 --- a/src/c_api/mcp_c_filter_api.cc +++ b/src/c_api/mcp_c_filter_api.cc @@ -103,7 +103,7 @@ class CApiFilter : public network::NetworkFilterBase { : callbacks_(callbacks), handle_(0) {} void setHandle(mcp_filter_t h) { handle_ = h; } - + // Add setter for callbacks void setCallbacks(const mcp_filter_callbacks_t& callbacks) { callbacks_ = callbacks; @@ -132,7 +132,8 @@ class CApiFilter : public network::NetworkFilterBase { } // New method for direct buffer handle processing - network::FilterStatus onDataWithHandle(uint64_t buffer_handle, bool end_stream) { + network::FilterStatus onDataWithHandle(uint64_t buffer_handle, + bool end_stream) { if (!callbacks_.on_data) { return network::FilterStatus::Continue; } @@ -691,21 +692,22 @@ MCP_API mcp_result_t mcp_filter_post_data(mcp_filter_t filter, if (data && length > 0) { buffer->add(data, length); } - + // Create a buffer handle and pass it to the callback auto buffer_handle = g_buffer_manager.store(buffer); - + // Call the filter's onDataWithHandle method to trigger callback execution - auto status = capi_filter->onDataWithHandle(buffer_handle, false); // end_stream = false - + auto status = capi_filter->onDataWithHandle(buffer_handle, + false); // end_stream = false + // If callback was provided, call it with the result if (callback) { - mcp_result_t result = (status == mcp::network::FilterStatus::Continue) - ? MCP_OK - : MCP_ERROR_INVALID_STATE; + mcp_result_t result = (status == mcp::network::FilterStatus::Continue) + ? MCP_OK + : MCP_ERROR_INVALID_STATE; callback(result, user_data); } - + return MCP_OK; } else { // For non-CApiFilter filters, just return success for now From 5d9f6ea71802fa143548cd53f37a06bec38b47ea Mon Sep 17 00:00:00 2001 From: gophergogo Date: Mon, 6 Oct 2025 09:54:19 -0700 Subject: [PATCH 10/33] Update C API to use int64_t for RequestId and ProgressToken (#121) Updated C API type conversion functions to handle int64_t instead of int for numeric RequestId and ProgressToken values, matching the core type definition changes. Changes: - mcp_c_type_conversions.h: Updated to_cpp_request_id, to_c_request_id, to_cpp_progress_token, and to_c_progress_token to use int64_t - mcp_c_bridge.h: Updated to_c_request_id_safe and to_cpp_request_id_safe to use int64_t This ensures C API builds correctly with the updated variant types and prevents overflow issues with large request IDs. --- include/mcp/c_api/mcp_c_bridge.h | 6 +++--- include/mcp/c_api/mcp_c_type_conversions.h | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/include/mcp/c_api/mcp_c_bridge.h b/include/mcp/c_api/mcp_c_bridge.h index 734b14e5..82bb47ce 100644 --- a/include/mcp/c_api/mcp_c_bridge.h +++ b/include/mcp/c_api/mcp_c_bridge.h @@ -648,20 +648,20 @@ inline mcp_request_id_t to_c_request_id_safe(const mcp::RequestId& id) { const auto& str = mcp::get(id); return mcp_request_id_create_string(str.c_str()); } else { - return mcp_request_id_create_number(mcp::get(id)); + return mcp_request_id_create_number(mcp::get(id)); } } inline mcp::RequestId to_cpp_request_id_safe(mcp_request_id_t id) { if (!id) { - return mcp::RequestId(0); + return mcp::RequestId(static_cast(0)); } if (mcp_request_id_is_string(id)) { const char* str = mcp_request_id_get_string(id); return mcp::RequestId(str ? std::string(str) : std::string()); } else { - return mcp::RequestId(static_cast(mcp_request_id_get_number(id))); + return mcp::RequestId(static_cast(mcp_request_id_get_number(id))); } } diff --git a/include/mcp/c_api/mcp_c_type_conversions.h b/include/mcp/c_api/mcp_c_type_conversions.h index 0c19fd97..252a2bbc 100644 --- a/include/mcp/c_api/mcp_c_type_conversions.h +++ b/include/mcp/c_api/mcp_c_type_conversions.h @@ -291,7 +291,7 @@ inline RequestId to_cpp_request_id(const mcp_request_id_t& id) { if (id.type == mcp_request_id::MCP_REQUEST_ID_STRING) { return RequestId(to_cpp_string(id.value.string_value)); } else { - return RequestId(static_cast(id.value.number_value)); + return RequestId(static_cast(id.value.number_value)); } } @@ -305,7 +305,7 @@ inline mcp_request_id_t to_c_request_id(const RequestId& id) { result.value.string_value = to_c_string(mcp::get(id)); } else { result.type = mcp_request_id::MCP_REQUEST_ID_NUMBER; - result.value.number_value = mcp::get(id); + result.value.number_value = mcp::get(id); } return result; } @@ -322,7 +322,7 @@ inline ProgressToken to_cpp_progress_token(const mcp_progress_token_t& token) { if (token.type == mcp_progress_token::MCP_PROGRESS_TOKEN_STRING) { return ProgressToken(to_cpp_string(token.value.string_value)); } else { - return ProgressToken(static_cast(token.value.number_value)); + return ProgressToken(static_cast(token.value.number_value)); } } @@ -336,7 +336,7 @@ inline mcp_progress_token_t to_c_progress_token(const ProgressToken& token) { result.value.string_value = to_c_string(mcp::get(token)); } else { result.type = mcp_progress_token::MCP_PROGRESS_TOKEN_NUMBER; - result.value.number_value = mcp::get(token); + result.value.number_value = mcp::get(token); } return result; } From 484c41b378d96bed56508a1e5772855efbea72e9 Mon Sep 17 00:00:00 2001 From: gophergogo Date: Mon, 6 Oct 2025 17:05:23 -0700 Subject: [PATCH 11/33] Reduce test output verbosity in build script (#122) Remove --verbose flag from ctest command to make test output less noisy. Now only shows test progress and summary instead of full gtest output. --- build.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.sh b/build.sh index f75e5c0d..6d36d5f5 100755 --- a/build.sh +++ b/build.sh @@ -134,9 +134,9 @@ fi # Run tests if requested if [ "$RUN_TESTS" = true ]; then print_status "Running tests..." - + # Run all tests using ctest - if GTEST_COLOR=1 ctest --output-on-failure --verbose -C $BUILD_TYPE; then + if GTEST_COLOR=1 ctest --output-on-failure -C $BUILD_TYPE; then print_success "All tests passed!" else print_error "Some tests failed" From 27d5d1153ae952440e047ab186e9dfff343ec439 Mon Sep 17 00:00:00 2001 From: gophergogo Date: Mon, 6 Oct 2025 17:41:08 -0700 Subject: [PATCH 12/33] Add format-cpp target for C++ only formatting (#122) Add make format-cpp target to format only C++ files with clang-format, separate from the all-languages format target. --- Makefile | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Makefile b/Makefile index 03abf14d..8bfab5f7 100644 --- a/Makefile +++ b/Makefile @@ -107,6 +107,16 @@ verbose: @./build.sh --verbose # Format all source files (C++ and TypeScript) +format-cpp: + @echo "Formatting C++ files with clang-format..." + @if command -v clang-format >/dev/null 2>&1; then \ + find . -path "./build*" -prune -o \( -name "*.h" -o -name "*.cpp" -o -name "*.cc" \) -print | xargs clang-format -i; \ + echo "C++ formatting complete."; \ + else \ + echo "Warning: clang-format not found, skipping C++ formatting."; \ + echo "Install clang-format to format C++ files: brew install clang-format (macOS) or apt-get install clang-format (Ubuntu)"; \ + fi + format: @echo "Formatting all source files..." @echo "Formatting C++ files with clang-format..." @@ -709,6 +719,7 @@ help: @echo "" @echo "┌─ CODE QUALITY TARGETS ──────────────────────────────────────────────┐" @echo "│ make format Auto-format all source files (C++, TypeScript, Python, Rust, Ruby, C#, Go, Java) │" + @echo "│ make format-cpp Format only C++ files with clang-format │" @echo "│ make format-ts Format only TypeScript files with prettier │" @echo "│ make format-python Format only Python files with black │" @echo "│ make format-rust Format only Rust files with rustfmt │" @@ -734,6 +745,7 @@ help: @echo "│ │" @echo "│ Development workflow: │" @echo "│ $$ make format # Format all code (C++, TypeScript, Python, Rust, Ruby, C#, Go, Java) │" + @echo "│ $$ make format-cpp # Format only C++ files │" @echo "│ $$ make format-ts # Format only TypeScript files │" @echo "│ $$ make format-python # Format only Python files │" @echo "│ $$ make format-rust # Format only Rust files │" From 7c589af5f9abdf74488618c73f571ea4e1d208df Mon Sep 17 00:00:00 2001 From: gophergogo Date: Mon, 6 Oct 2025 17:54:01 -0700 Subject: [PATCH 13/33] Linux build fix: MCP_SO_ATTACH_REUSEPORT_CBPF declaration order (#122) Move MCP_SO_ATTACH_REUSEPORT_CBPF constant definition to top of file before it's used in ReusePortSocketOption::setOptionForListen(). Previously it was defined after use, causing compilation error. --- src/network/socket_option_impl.cc | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/src/network/socket_option_impl.cc b/src/network/socket_option_impl.cc index fbe59ce5..87dd6b02 100644 --- a/src/network/socket_option_impl.cc +++ b/src/network/socket_option_impl.cc @@ -17,6 +17,16 @@ namespace mcp { namespace network { +// Socket option name constants - must be defined before use +#ifdef SO_ATTACH_REUSEPORT_CBPF +#define MCP_ATTACH_REUSEPORT_CBPF \ + MCP_MAKE_SOCKET_OPTION_NAME(SOL_SOCKET, SO_ATTACH_REUSEPORT_CBPF) +#else +#define MCP_ATTACH_REUSEPORT_CBPF SocketOptionName() +#endif + +const SocketOptionName MCP_SO_ATTACH_REUSEPORT_CBPF = MCP_ATTACH_REUSEPORT_CBPF; + // ===== Base SocketOption Implementation ===== SocketOptionImpl::SocketOptionImpl(const SocketOptionName& optname, @@ -449,17 +459,6 @@ const SocketOptionName SOCKET_TCP_KEEPCNT = const SocketOptionName SOCKET_TCP_KEEPCNT; #endif -// Fix the macro reference -#ifdef SO_ATTACH_REUSEPORT_CBPF -#define MCP_ATTACH_REUSEPORT_CBPF \ - MCP_MAKE_SOCKET_OPTION_NAME(SOL_SOCKET, SO_ATTACH_REUSEPORT_CBPF) -#else -#define MCP_ATTACH_REUSEPORT_CBPF SocketOptionName() -#endif - -// Define the constant used in the code -const SocketOptionName MCP_SO_ATTACH_REUSEPORT_CBPF = MCP_ATTACH_REUSEPORT_CBPF; - // IPv6 transparent option #ifdef IPV6_TRANSPARENT const SocketOptionName SOCKET_IPV6_TRANSPARENT = From a558fb482f882ea0dca1a0ec3e811781a74cc03a Mon Sep 17 00:00:00 2001 From: gophergogo Date: Mon, 6 Oct 2025 18:01:24 -0700 Subject: [PATCH 14/33] Linux build fix: Remove unused C++17 filesystem include from log_sink.cc (#122) The filesystem header is C++17 only and wasn't being used. Removed unused includes to maintain C++14 compatibility for default builds. --- src/logging/log_sink.cc | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/logging/log_sink.cc b/src/logging/log_sink.cc index a653cd85..5a8f612a 100644 --- a/src/logging/log_sink.cc +++ b/src/logging/log_sink.cc @@ -1,11 +1,5 @@ #include "mcp/logging/log_sink.h" -#include -#include -#include -#include -#include - namespace mcp { namespace logging { From 490feb4a24db6b8f54d906f9d0cb263fc3cba7c0 Mon Sep 17 00:00:00 2001 From: gophergogo Date: Mon, 6 Oct 2025 18:07:53 -0700 Subject: [PATCH 15/33] Linux build fix: Replace designated initializers with field assignments for C++14 compatibility (#122) Replace C++20-style designated initializers with regular field assignments to support older compilers (GCC 6.x on Ubuntu 18). Designated initializers with skipped fields are not supported in C++14/C++17. --- src/network/connection_state_machine.cc | 32 +++++++++++-------------- 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/src/network/connection_state_machine.cc b/src/network/connection_state_machine.cc index 5879447b..7856725f 100644 --- a/src/network/connection_state_machine.cc +++ b/src/network/connection_state_machine.cc @@ -328,15 +328,13 @@ void ConnectionStateMachine::forceTransition(ConnectionMachineState new_state, auto old_state = current_state_.load(); // Create transition context - StateTransitionContext context{ - .from_state = old_state, - .to_state = new_state, - .triggering_event = ConnectionStateMachineEvent::ResetRequested, - .timestamp = std::chrono::steady_clock::now(), - .reason = "FORCED: " + reason, - .time_in_previous_state = getTimeInCurrentState()}; - - // Update metrics + StateTransitionContext context; + context.from_state = old_state; + context.to_state = new_state; + context.triggering_event = ConnectionStateMachineEvent::ResetRequested; + context.timestamp = std::chrono::steady_clock::now(); + context.reason = "FORCED: " + reason; + context.time_in_previous_state = getTimeInCurrentState(); context.bytes_read_in_state = state_bytes_read_; context.bytes_written_in_state = state_bytes_written_; state_bytes_read_ = 0; @@ -474,15 +472,13 @@ bool ConnectionStateMachine::transitionTo(ConnectionMachineState new_state, transition_in_progress_ = true; // Create transition context - StateTransitionContext context{ - .from_state = old_state, - .to_state = new_state, - .triggering_event = event, - .timestamp = std::chrono::steady_clock::now(), - .reason = reason, - .time_in_previous_state = getTimeInCurrentState()}; - - // Update metrics + StateTransitionContext context; + context.from_state = old_state; + context.to_state = new_state; + context.triggering_event = event; + context.timestamp = std::chrono::steady_clock::now(); + context.reason = reason; + context.time_in_previous_state = getTimeInCurrentState(); context.bytes_read_in_state = state_bytes_read_; context.bytes_written_in_state = state_bytes_written_; state_bytes_read_ = 0; From 5343cd4c73c60e5947517c715282e0c42f9f589e Mon Sep 17 00:00:00 2001 From: gophergogo Date: Mon, 6 Oct 2025 20:16:45 -0700 Subject: [PATCH 16/33] Linux build fix: Fix designated initializers and reference type issues for C++14 (#122) Replace designated initializers with explicit field assignments in listener implementations for C++14 compatibility. Also fix reference_wrapper type mismatch in getAllListeners() by explicitly casting ActiveListener to base Listener class. --- src/network/listener_impl.cc | 14 ++++++++------ src/network/tcp_server_listener_impl.cc | 8 ++++++-- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/network/listener_impl.cc b/src/network/listener_impl.cc index c76144b5..065d7898 100644 --- a/src/network/listener_impl.cc +++ b/src/network/listener_impl.cc @@ -101,13 +101,14 @@ VoidResult ActiveListener::listen() { // Create socket if (config_.bind_to_port) { // Use the global createListenSocket function + SocketCreationOptions socket_opts; + socket_opts.non_blocking = true; + socket_opts.close_on_exec = true; + socket_opts.reuse_address = true; // Essential for server sockets + auto socket = createListenSocket( config_.address, - SocketCreationOptions{ - .non_blocking = true, - .close_on_exec = true, - .reuse_address = true // Essential for server sockets - }, + socket_opts, config_.bind_to_port); if (!socket) { @@ -387,7 +388,8 @@ std::vector> ListenerManagerImpl::getAllListeners() { std::vector> result; for (auto& pair : listeners_) { - result.push_back(std::ref(*pair.second)); + // Cast to base class reference explicitly + result.push_back(std::ref(static_cast(*pair.second))); } return result; } diff --git a/src/network/tcp_server_listener_impl.cc b/src/network/tcp_server_listener_impl.cc index dd21e22c..06598321 100644 --- a/src/network/tcp_server_listener_impl.cc +++ b/src/network/tcp_server_listener_impl.cc @@ -317,10 +317,14 @@ TcpActiveListener::TcpActiveListener(event::Dispatcher& dispatcher, << config_.address->asString() << std::endl; std::cerr << "[DEBUG] About to call createListenSocket..." << std::endl; // Create and bind socket + SocketCreationOptions socket_opts; + socket_opts.non_blocking = true; + socket_opts.close_on_exec = true; + socket_opts.reuse_address = true; + auto socket_result = createListenSocket( config_.address, - SocketCreationOptions{ - .non_blocking = true, .close_on_exec = true, .reuse_address = true}, + socket_opts, config_.bind_to_port); std::cerr << "[DEBUG] createListenSocket returned: " << (socket_result ? "SUCCESS" : "NULL") << std::endl; From ba27380dd96c9f5ba029efc4c3e93b3138918869 Mon Sep 17 00:00:00 2001 From: gophergogo Date: Mon, 6 Oct 2025 20:22:05 -0700 Subject: [PATCH 17/33] Linux build fix: Fix remaining designated initializer in tcp_server_listener_impl.cc (#122) Replace designated initializer at line 539 with explicit field assignments for C++14 compatibility. --- src/network/tcp_server_listener_impl.cc | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/network/tcp_server_listener_impl.cc b/src/network/tcp_server_listener_impl.cc index 06598321..441cd517 100644 --- a/src/network/tcp_server_listener_impl.cc +++ b/src/network/tcp_server_listener_impl.cc @@ -533,10 +533,14 @@ std::unique_ptr ListenerFactory::createTcpListener( SocketSharedPtr socket = config.socket; if (!socket && config.address) { // Create and bind socket + SocketCreationOptions socket_opts; + socket_opts.non_blocking = true; + socket_opts.close_on_exec = true; + socket_opts.reuse_address = true; + auto socket_result = createListenSocket( config.address, - SocketCreationOptions{ - .non_blocking = true, .close_on_exec = true, .reuse_address = true}, + socket_opts, config.bind_to_port); if (socket_result) { From 878ff5562293c54e9642e3e79208e13c3d03e572 Mon Sep 17 00:00:00 2001 From: gophergogo Date: Mon, 6 Oct 2025 20:26:29 -0700 Subject: [PATCH 18/33] Linux build fix: Fix missing headers and C++17 structured bindings (#122) Add missing and headers to ssl_context.h. Replace C++17 structured bindings with traditional pair access in ssl_state_machine.cc for C++14 compatibility. --- include/mcp/transport/ssl_context.h | 2 ++ src/transport/ssl_state_machine.cc | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/include/mcp/transport/ssl_context.h b/include/mcp/transport/ssl_context.h index 81ba5a35..89d71f29 100644 --- a/include/mcp/transport/ssl_context.h +++ b/include/mcp/transport/ssl_context.h @@ -17,9 +17,11 @@ #ifndef MCP_TRANSPORT_SSL_CONTEXT_H #define MCP_TRANSPORT_SSL_CONTEXT_H +#include #include #include #include +#include #include #include "mcp/core/result.h" diff --git a/src/transport/ssl_state_machine.cc b/src/transport/ssl_state_machine.cc index 2151964a..c84d9ba3 100644 --- a/src/transport/ssl_state_machine.cc +++ b/src/transport/ssl_state_machine.cc @@ -533,8 +533,8 @@ void SslStateMachine::executeExitAction(SslSocketState state, void SslStateMachine::notifyStateChange(SslSocketState old_state, SslSocketState new_state) { // Already in dispatcher thread, no locking needed - for (const auto& [id, callback] : state_listeners_) { - callback(old_state, new_state); + for (const auto& listener : state_listeners_) { + listener.second(old_state, new_state); } } From 7b447fcfdff41baa6370117a4ce7828a11af93e3 Mon Sep 17 00:00:00 2001 From: gophergogo Date: Mon, 6 Oct 2025 20:28:50 -0700 Subject: [PATCH 19/33] Linux build fix: Replace C++17 structured bindings with traditional pair access (#122) Replace all structured bindings (C++17 feature) with traditional .first/.second access for C++14 compatibility in: - http_parser.cc - mcp_client.cc - log_formatter.cc - logger_registry.cc --- src/client/mcp_client.cc | 12 ++++++------ src/http/http_parser.cc | 8 +++++--- src/logging/log_formatter.cc | 8 ++++++-- src/logging/logger_registry.cc | 27 ++++++++++++++++++++------- 4 files changed, 37 insertions(+), 18 deletions(-) diff --git a/src/client/mcp_client.cc b/src/client/mcp_client.cc index 9b6b9887..ad8dfb31 100644 --- a/src/client/mcp_client.cc +++ b/src/client/mcp_client.cc @@ -808,8 +808,8 @@ std::future McpClient::callTool( params["name"] = name; if (arguments.has_value()) { // Arguments is a Metadata object, merge it - for (const auto& [key, value] : arguments.value()) { - params["arguments." + key] = value; + for (const auto& arg : arguments.value()) { + params["arguments." + arg.first] = arg.second; } } @@ -889,8 +889,8 @@ std::future McpClient::getPrompt( params["name"] = name; if (arguments.has_value()) { // Arguments is a Metadata object, merge it - for (const auto& [key, value] : arguments.value()) { - params["arguments." + key] = value; + for (const auto& arg : arguments.value()) { + params["arguments." + arg.first] = arg.second; } } @@ -1188,8 +1188,8 @@ std::vector> McpClient::sendBatch( const std::vector>>& requests) { std::vector> futures; - for (const auto& [method, params] : requests) { - futures.push_back(sendRequest(method, params)); + for (const auto& request : requests) { + futures.push_back(sendRequest(request.first, request.second)); } return futures; diff --git a/src/http/http_parser.cc b/src/http/http_parser.cc index 0de9ea5d..98ffda11 100644 --- a/src/http/http_parser.cc +++ b/src/http/http_parser.cc @@ -129,7 +129,9 @@ class HttpHeadersImpl : public HttpHeaders { HttpHeaderMap getMap() const override { HttpHeaderMap result; - for (const auto& [name, values] : headers_) { + for (const auto& header : headers_) { + const auto& name = header.first; + const auto& values = header.second; if (!values.empty()) { // Join multiple values with comma std::string joined; @@ -146,8 +148,8 @@ class HttpHeadersImpl : public HttpHeaders { void forEach(std::function cb) const override { - for (const auto& [name, value] : ordered_headers_) { - cb(name, value); + for (const auto& header : ordered_headers_) { + cb(header.first, header.second); } } diff --git a/src/logging/log_formatter.cc b/src/logging/log_formatter.cc index 9ae02bb1..c37b7e24 100644 --- a/src/logging/log_formatter.cc +++ b/src/logging/log_formatter.cc @@ -78,7 +78,9 @@ std::string DefaultFormatter::format(const LogMessage& msg) const { if (!msg.key_values.empty()) { oss << " {"; bool first = true; - for (const auto& [key, value] : msg.key_values) { + for (const auto& kv : msg.key_values) { + const auto& key = kv.first; + const auto& value = kv.second; if (!first) oss << ", "; oss << key << "=" << value; @@ -167,7 +169,9 @@ std::string JsonFormatter::format(const LogMessage& msg) const { if (!msg.key_values.empty()) { oss << ",\"metadata\":{"; bool first = true; - for (const auto& [key, value] : msg.key_values) { + for (const auto& kv : msg.key_values) { + const auto& key = kv.first; + const auto& value = kv.second; if (!first) oss << ","; oss << "\"" << escapeJson(key) << "\":\"" << escapeJson(value) << "\""; diff --git a/src/logging/logger_registry.cc b/src/logging/logger_registry.cc index 8fafb861..85413700 100644 --- a/src/logging/logger_registry.cc +++ b/src/logging/logger_registry.cc @@ -70,10 +70,13 @@ void LoggerRegistry::setGlobalLevel(LogLevel level) { global_level_ = level; // Update all existing loggers - for (auto& [name, logger] : loggers_) { + for (auto& logger_pair : loggers_) { + auto& name = logger_pair.first; + auto& logger = logger_pair.second; // Check if logger has specific pattern bool has_pattern = false; - for (const auto& [pattern, _] : patterns_) { + for (const auto& pattern_pair : patterns_) { + const auto& pattern = pattern_pair.pattern; std::regex re(pattern); if (std::regex_match(name, re)) { has_pattern = true; @@ -93,7 +96,9 @@ void LoggerRegistry::setComponentLevel(Component component, LogLevel level) { // Update existing component loggers std::string comp_prefix = componentToString(component); - for (auto& [name, logger] : loggers_) { + for (auto& logger_pair : loggers_) { + auto& name = logger_pair.first; + auto& logger = logger_pair.second; if (name.find(comp_prefix + ".") == 0) { logger->setLevel(level); } @@ -107,7 +112,9 @@ void LoggerRegistry::setPattern(const std::string& pattern, LogLevel level) { patterns_.emplace_back(pattern, level); // Update existing loggers that match the pattern - for (auto& [name, logger] : loggers_) { + for (auto& logger_pair : loggers_) { + auto& name = logger_pair.first; + auto& logger = logger_pair.second; if (std::regex_match(name, patterns_.back().pattern)) { logger->setLevel(level); } @@ -188,7 +195,9 @@ std::vector LoggerRegistry::getLoggerNames() const { std::vector names; names.reserve(loggers_.size()); - for (const auto& [name, logger] : loggers_) { + for (const auto& logger_pair : loggers_) { + const auto& name = logger_pair.first; + const auto& logger = logger_pair.second; names.push_back(name); } @@ -204,7 +213,9 @@ void LoggerRegistry::setBloomFilter(bool enabled, bloom_filter_ = BloomFilter(size, num_hashes); // Add all existing logger names - for (const auto& [name, logger] : loggers_) { + for (const auto& logger_pair : loggers_) { + const auto& name = logger_pair.first; + const auto& logger = logger_pair.second; bloom_filter_.add(name); logger->setBloomFilterHint(&bloom_filter_); } @@ -212,7 +223,9 @@ void LoggerRegistry::setBloomFilter(bool enabled, bloom_filter_.clear(); // Clear bloom filter hints - for (auto& [name, logger] : loggers_) { + for (auto& logger_pair : loggers_) { + auto& name = logger_pair.first; + auto& logger = logger_pair.second; logger->setBloomFilterHint(nullptr); } } From 6dc98e1290cecfa3c5cabac0229cff372bc57b02 Mon Sep 17 00:00:00 2001 From: gophergogo Date: Mon, 6 Oct 2025 21:35:40 -0700 Subject: [PATCH 20/33] Linux build fix: Enable position-independent code for llhttp static library (#122) Add POSITION_INDEPENDENT_CODE property to llhttp library to enable linking into shared libraries. Fixes linker error on Linux when building shared libgopher-mcp.so. --- CMakeLists.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 11cda1aa..1aebfcdd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -194,7 +194,10 @@ if(MCP_USE_LLHTTP) add_library(llhttp STATIC ${LLHTTP_SOURCES}) target_include_directories(llhttp PUBLIC ${llhttp_SOURCE_DIR}/include) - + + # Enable position-independent code for shared library linking + set_target_properties(llhttp PROPERTIES POSITION_INDEPENDENT_CODE ON) + # Disable warnings for third-party code if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") target_compile_options(llhttp PRIVATE -w) From 3fcd07d4f9b5225fd7e2d588adb41f071c4ba213 Mon Sep 17 00:00:00 2001 From: gophergogo Date: Mon, 6 Oct 2025 21:38:51 -0700 Subject: [PATCH 21/33] Linux build fix: Replace filesystem header with C functions in test_log_sink.cc (#122) Replace C++17 with C functions for C++14 compatibility: - fs::exists() -> stat() based file_exists() - fs::remove() -> std::remove() --- tests/logging/test_log_sink.cc | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/tests/logging/test_log_sink.cc b/tests/logging/test_log_sink.cc index 85bda95c..dc180156 100644 --- a/tests/logging/test_log_sink.cc +++ b/tests/logging/test_log_sink.cc @@ -1,13 +1,25 @@ -#include +#include #include #include +#include #include #include "mcp/logging/log_sink.h" using namespace mcp::logging; -namespace fs = std::__fs::filesystem; + +// Helper functions to replace std::filesystem +namespace { +bool file_exists(const std::string& path) { + struct stat buffer; + return (stat(path.c_str(), &buffer) == 0); +} + +void remove_file(const std::string& path) { + std::remove(path.c_str()); +} +} // namespace class TestLogSink : public LogSink { public: @@ -44,10 +56,10 @@ class LogSinkTest : public ::testing::Test { void TearDown() override { // Clean up test files for (const auto& file : test_files_) { - fs::remove(file); + remove_file(file); // Also remove rotated files for (int i = 1; i <= 10; ++i) { - fs::remove(file + "." + std::to_string(i)); + remove_file(file + "." + std::to_string(i)); } } } @@ -152,7 +164,7 @@ TEST_F(LogSinkTest, RotatingFileSinkBasic) { } // Check file exists and has content - EXPECT_TRUE(fs::exists(test_file)); + EXPECT_TRUE(file_exists(test_file)); std::ifstream file(test_file); std::string content((std::istreambuf_iterator(file)), @@ -185,8 +197,8 @@ TEST_F(LogSinkTest, RotatingFileSinkRotation) { } // Check that rotation happened - EXPECT_TRUE(fs::exists(test_file)); - EXPECT_TRUE(fs::exists(test_file + ".1")); + EXPECT_TRUE(file_exists(test_file)); + EXPECT_TRUE(file_exists(test_file + ".1")); } TEST_F(LogSinkTest, SinkGuardRAII) { From 1afe8bd1a774198e931c06888b19c36ae33da8d0 Mon Sep 17 00:00:00 2001 From: gophergogo Date: Mon, 6 Oct 2025 21:41:03 -0700 Subject: [PATCH 22/33] Linux build fix: Enable position-independent code for nghttp2 static library (#122) Add POSITION_INDEPENDENT_CODE property to nghttp2_static library to enable linking into shared libraries. Fixes linker error on Linux when building shared libgopher-mcp.so. --- CMakeLists.txt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1aebfcdd..9a179dbe 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -248,7 +248,12 @@ if(MCP_USE_NGHTTP2) message(STATUS "nghttp2 is a larger dependency and requires compilation. Please be patient.") FetchContent_MakeAvailable(nghttp2) message(STATUS "nghttp2 download and configuration complete.") - + + # Enable position-independent code for shared library linking + if(TARGET nghttp2_static) + set_target_properties(nghttp2_static PROPERTIES POSITION_INDEPENDENT_CODE ON) + endif() + set(NGHTTP2_FOUND TRUE) set(NGHTTP2_INCLUDE_DIRS ${nghttp2_SOURCE_DIR}/lib/includes From 4481de819249c8c21b7251d3f0528a7ff02e86f1 Mon Sep 17 00:00:00 2001 From: gophergogo Date: Mon, 6 Oct 2025 21:46:40 -0700 Subject: [PATCH 23/33] Linux build fix: Fix string_literal for C++14 compatibility (#122) Remove constexpr from string_literal constructor and operator== for C++14 builds since C++14 doesn't allow loops in constexpr functions. Keep constexpr for C++17+ builds. Update tests to use runtime checks instead of static_assert for C++14. --- include/mcp/core/type_helpers.h | 14 ++++++++++++-- tests/core/test_mcp_type_helpers.cc | 19 ++++++++++--------- 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/include/mcp/core/type_helpers.h b/include/mcp/core/type_helpers.h index 64f3f395..cd892c51 100644 --- a/include/mcp/core/type_helpers.h +++ b/include/mcp/core/type_helpers.h @@ -234,16 +234,26 @@ template struct string_literal { char value[N]; +#if __cplusplus >= 201703L + // C++17 and later: can use constexpr with loops constexpr string_literal(const char (&str)[N]) { for (size_t i = 0; i < N; ++i) { value[i] = str[i]; } } +#else + // C++14: constexpr constructors can't have loops + string_literal(const char (&str)[N]) { + for (size_t i = 0; i < N; ++i) { + value[i] = str[i]; + } + } +#endif constexpr const char* c_str() const { return value; } constexpr size_t size() const { return N - 1; } - constexpr bool operator==(const string_literal& other) const { + bool operator==(const string_literal& other) const { for (size_t i = 0; i < N; ++i) { if (value[i] != other.value[i]) return false; @@ -254,7 +264,7 @@ struct string_literal { // Deduction guide for C++17, but we'll use make function for C++14 template -constexpr string_literal make_string_literal(const char (&str)[N]) { +inline string_literal make_string_literal(const char (&str)[N]) { return string_literal(str); } diff --git a/tests/core/test_mcp_type_helpers.cc b/tests/core/test_mcp_type_helpers.cc index 8844bfe4..9294f9c1 100644 --- a/tests/core/test_mcp_type_helpers.cc +++ b/tests/core/test_mcp_type_helpers.cc @@ -474,12 +474,13 @@ TEST_F(MCPTypeHelpersTest, ObjectBuilderComplex) { TEST_F(MCPTypeHelpersTest, StringLiteralBasic) { // Test construction and comparison - constexpr auto lit1 = make_string_literal("hello"); - constexpr auto lit2 = make_string_literal("hello"); - constexpr auto lit3 = make_string_literal("world"); + auto lit1 = make_string_literal("hello"); + auto lit2 = make_string_literal("hello"); + auto lit3 = make_string_literal("world"); - static_assert(lit1 == lit2, "Same literals should be equal"); - static_assert(!(lit1 == lit3), "Different literals should not be equal"); + // Test equality + EXPECT_TRUE(lit1 == lit2); + EXPECT_FALSE(lit1 == lit3); // Test c_str and size EXPECT_STREQ(lit1.c_str(), "hello"); @@ -489,24 +490,24 @@ TEST_F(MCPTypeHelpersTest, StringLiteralBasic) { EXPECT_EQ(lit3.size(), 5u); // Test empty string - constexpr auto empty = make_string_literal(""); + auto empty = make_string_literal(""); EXPECT_STREQ(empty.c_str(), ""); EXPECT_EQ(empty.size(), 0u); } TEST_F(MCPTypeHelpersTest, StringLiteralEdgeCases) { // Test with special characters - constexpr auto special = make_string_literal("Hello\nWorld\t!"); + auto special = make_string_literal("Hello\nWorld\t!"); EXPECT_STREQ(special.c_str(), "Hello\nWorld\t!"); EXPECT_EQ(special.size(), 13u); // Test with numbers - constexpr auto numbers = make_string_literal("12345"); + auto numbers = make_string_literal("12345"); EXPECT_STREQ(numbers.c_str(), "12345"); EXPECT_EQ(numbers.size(), 5u); // Test long string - constexpr auto long_str = make_string_literal( + auto long_str = make_string_literal( "This is a very long string literal that tests the string_literal " "template"); EXPECT_EQ(long_str.size(), 73u); From 94d5ca6e676e37f13df1c5febc2e0f0ec84b1535 Mon Sep 17 00:00:00 2001 From: gophergogo Date: Mon, 6 Oct 2025 21:53:43 -0700 Subject: [PATCH 24/33] Linux build fix: Fix atomic time_point initialization in test_event_loop.cc (#122) Explicitly initialize std::atomic in constructor initializer list. Default construction of atomic complex types is not supported in older compilers (GCC 7). --- tests/event/test_event_loop.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/event/test_event_loop.cc b/tests/event/test_event_loop.cc index 4c7185ff..b107d3d4 100644 --- a/tests/event/test_event_loop.cc +++ b/tests/event/test_event_loop.cc @@ -457,7 +457,9 @@ TEST_F(EventLoopTest, DISABLED_Watchdog) { // Watchdog registration creates internal timers which need dispatcher thread class TestWatchdog : public WatchDog { public: - TestWatchdog() : thread_id_(std::this_thread::get_id()) {} + TestWatchdog() + : thread_id_(std::this_thread::get_id()), + last_touch_time_(std::chrono::steady_clock::now()) {} void touch() override { touch_count_++; From 6b40fbeae9d2b897dd80aa6960a0b92ad2c6a885 Mon Sep 17 00:00:00 2001 From: gophergogo Date: Mon, 6 Oct 2025 22:03:33 -0700 Subject: [PATCH 25/33] Linux build fix: Replace designated initializers in test_tcp_listener.cc (#122) Replace SocketCreationOptions designated initializers with lambda functions returning initialized structs for C++14 compatibility. --- tests/network/test_tcp_listener.cc | 45 +++++++++++++++++++++++------- 1 file changed, 35 insertions(+), 10 deletions(-) diff --git a/tests/network/test_tcp_listener.cc b/tests/network/test_tcp_listener.cc index f81ca630..b9e33876 100644 --- a/tests/network/test_tcp_listener.cc +++ b/tests/network/test_tcp_listener.cc @@ -269,8 +269,13 @@ TEST_F(TcpListenerTest, CreateAndEnable) { // Create socket using MCP socket interface auto socket = createListenSocket( address_, - SocketCreationOptions{ - .non_blocking = true, .close_on_exec = true, .reuse_address = true}, + []() { + SocketCreationOptions opts; + opts.non_blocking = true; + opts.close_on_exec = true; + opts.reuse_address = true; + return opts; + }(), true); ASSERT_NE(socket, nullptr); @@ -306,8 +311,13 @@ TEST_F(TcpListenerTest, RejectFraction) { // Create socket using MCP abstractions auto socket = createListenSocket( address_, - SocketCreationOptions{ - .non_blocking = true, .close_on_exec = true, .reuse_address = true}, + []() { + SocketCreationOptions opts; + opts.non_blocking = true; + opts.close_on_exec = true; + opts.reuse_address = true; + return opts; + }(), true); ASSERT_NE(socket, nullptr); @@ -336,8 +346,13 @@ TEST_F(TcpListenerTest, ConnectionAcceptanceWithMcpIo) { executeInDispatcher([this, &port]() { auto listen_socket = createListenSocket( address_, - SocketCreationOptions{ - .non_blocking = true, .close_on_exec = true, .reuse_address = true}, + []() { + SocketCreationOptions opts; + opts.non_blocking = true; + opts.close_on_exec = true; + opts.reuse_address = true; + return opts; + }(), true); ASSERT_NE(listen_socket, nullptr); @@ -456,8 +471,13 @@ TEST_F(TcpListenerTest, DataTransferUsingMcpBuffer) { executeInDispatcher([this, &port]() { auto listen_socket = createListenSocket( address_, - SocketCreationOptions{ - .non_blocking = true, .close_on_exec = true, .reuse_address = true}, + []() { + SocketCreationOptions opts; + opts.non_blocking = true; + opts.close_on_exec = true; + opts.reuse_address = true; + return opts; + }(), true); ASSERT_NE(listen_socket, nullptr); @@ -539,8 +559,13 @@ TEST_F(TcpListenerTest, BatchedAccepts) { // Create listener with batched accepts auto listen_socket = createListenSocket( address_, - SocketCreationOptions{ - .non_blocking = true, .close_on_exec = true, .reuse_address = true}, + []() { + SocketCreationOptions opts; + opts.non_blocking = true; + opts.close_on_exec = true; + opts.reuse_address = true; + return opts; + }(), true); ASSERT_NE(listen_socket, nullptr); From 6d80aebda86fa63b8ba85dbdb949329aed30136d Mon Sep 17 00:00:00 2001 From: gophergogo Date: Mon, 6 Oct 2025 22:13:41 -0700 Subject: [PATCH 26/33] Linux build fix: Remove nothrow attribute for GCC/Clang (#122) GCC 7 doesn't allow __attribute__((nothrow)) on function definitions, only on declarations. Remove it for GCC/Clang builds to fix C API compilation errors. --- include/mcp/c_api/mcp_c_types.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/mcp/c_api/mcp_c_types.h b/include/mcp/c_api/mcp_c_types.h index a25ff068..845afab9 100644 --- a/include/mcp/c_api/mcp_c_types.h +++ b/include/mcp/c_api/mcp_c_types.h @@ -39,7 +39,7 @@ extern "C" { #define MCP_API_EXPORT __attribute__((visibility("default"))) #define MCP_API_IMPORT #define MCP_CALLBACK -#define MCP_NOEXCEPT __attribute__((nothrow)) +#define MCP_NOEXCEPT // GCC 7 doesn't allow attributes on function definitions #else #define MCP_API_EXPORT #define MCP_API_IMPORT From 68d999c2fca96981539b6f51c7ee1e325cb4ab96 Mon Sep 17 00:00:00 2001 From: gophergogo Date: Mon, 6 Oct 2025 22:16:34 -0700 Subject: [PATCH 27/33] Linux build fix: Add missing cstring header (#122) Add header for strncpy and memset functions used in C API error handling. --- src/c_api/mcp_c_types_impl.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/c_api/mcp_c_types_impl.cc b/src/c_api/mcp_c_types_impl.cc index fb6d37bd..789457fb 100644 --- a/src/c_api/mcp_c_types_impl.cc +++ b/src/c_api/mcp_c_types_impl.cc @@ -7,6 +7,7 @@ */ #include +#include #include #include #include From 632c8ac97f9990de6becefc1bb3f5597ac3a25a1 Mon Sep 17 00:00:00 2001 From: gophergogo Date: Mon, 6 Oct 2025 22:18:18 -0700 Subject: [PATCH 28/33] Linux build fix: Guard SO_NOSIGPIPE with ifdef (#122) SO_NOSIGPIPE is macOS-specific and doesn't exist on Linux. Add conditional compilation guard to only use it when available. --- tests/network/test_connection_utility.cc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/network/test_connection_utility.cc b/tests/network/test_connection_utility.cc index ed5b1356..f2c0220a 100644 --- a/tests/network/test_connection_utility.cc +++ b/tests/network/test_connection_utility.cc @@ -286,7 +286,11 @@ TEST_F(ConnectionUtilityTest, ComprehensiveSocketStateValidation) { if (opt.level == IPPROTO_TCP && opt.optname == TCP_NODELAY) { EXPECT_NE(0, value) << "Option " << opt.name << " should be enabled"; } else if (opt.level == SOL_SOCKET && - (opt.optname == SO_KEEPALIVE || opt.optname == SO_NOSIGPIPE)) { + (opt.optname == SO_KEEPALIVE +#ifdef SO_NOSIGPIPE + || opt.optname == SO_NOSIGPIPE +#endif + )) { EXPECT_NE(0, value) << "Option " << opt.name << " should be enabled"; } else { EXPECT_EQ(opt.expected_value, value) From cfb6e7ee9434d6ea343fa19c4194fc600c6957d0 Mon Sep 17 00:00:00 2001 From: gophergogo Date: Mon, 6 Oct 2025 22:25:38 -0700 Subject: [PATCH 29/33] Linux build fix: Use int64_t instead of long long in example (#121) Replace 'long long' with 'int64_t' to match MetadataValue variant type definition. Fixes template instantiation errors on Linux. --- examples/mcp/mcp_example_server.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/mcp/mcp_example_server.cc b/examples/mcp/mcp_example_server.cc index 15726bbb..ee429d28 100644 --- a/examples/mcp/mcp_example_server.cc +++ b/examples/mcp/mcp_example_server.cc @@ -251,13 +251,13 @@ CallToolResult executeSampleTool(const std::string& name, : ""; double a = holds_alternative(a_it->second) ? get(a_it->second) - : (holds_alternative(a_it->second) - ? static_cast(get(a_it->second)) + : (holds_alternative(a_it->second) + ? static_cast(get(a_it->second)) : 0.0); double b = holds_alternative(b_it->second) ? get(b_it->second) - : (holds_alternative(b_it->second) - ? static_cast(get(b_it->second)) + : (holds_alternative(b_it->second) + ? static_cast(get(b_it->second)) : 0.0); double calc_result = 0; From a4c56f16a53876ede861b11e060a716729221178 Mon Sep 17 00:00:00 2001 From: gophergogo Date: Mon, 6 Oct 2025 22:30:15 -0700 Subject: [PATCH 30/33] Linux build fix: Add missing csignal header to event_loop_example (#122) Add header for SIGINT and signal() functions used in the example. This header is required for signal handling functionality on Ubuntu 18 with GCC 7. --- examples/event_loop_example.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/event_loop_example.cc b/examples/event_loop_example.cc index b0e0fdba..0dd35831 100644 --- a/examples/event_loop_example.cc +++ b/examples/event_loop_example.cc @@ -1,5 +1,6 @@ #include #include +#include #include #include #include From 3dff7b7daa81aa1180bfaf95a0daf7707217cc20 Mon Sep 17 00:00:00 2001 From: gophergogo Date: Mon, 6 Oct 2025 22:32:16 -0700 Subject: [PATCH 31/33] Linux build fix: Add algorithm header and explicit lambda return type (#122) Add missing header for std::find and add explicit bool return type to lambda to work around GCC 7 type deduction issue with condition_variable. --- tests/c_api/test_mcp_c_filter_api.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/c_api/test_mcp_c_filter_api.cc b/tests/c_api/test_mcp_c_filter_api.cc index 8f58762a..b4d65563 100644 --- a/tests/c_api/test_mcp_c_filter_api.cc +++ b/tests/c_api/test_mcp_c_filter_api.cc @@ -14,6 +14,7 @@ * - Statistics and monitoring */ +#include #include #include #include @@ -503,7 +504,7 @@ class CallbackTracker { bool waitForCallback(const std::string& name, std::chrono::milliseconds timeout) { std::unique_lock lock(mutex_); - return cv_.wait_for(lock, timeout, [this, &name]() { + return cv_.wait_for(lock, timeout, [this, &name]() -> bool { return std::find(callbacks_.begin(), callbacks_.end(), name) != callbacks_.end(); }); From 29241addc56e08b39e421092582e424baa463964 Mon Sep 17 00:00:00 2001 From: gophergogo Date: Mon, 6 Oct 2025 22:34:27 -0700 Subject: [PATCH 32/33] Linux build fix: Replace filesystem header with C functions in logging test (#122) Replace C++17 with and , using stat() for file_exists() and std::remove() for file deletion to support C++14 on GCC 7. --- tests/c_api/test_mcp_c_logging_api.cc | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/tests/c_api/test_mcp_c_logging_api.cc b/tests/c_api/test_mcp_c_logging_api.cc index d92ace04..e07c32da 100644 --- a/tests/c_api/test_mcp_c_logging_api.cc +++ b/tests/c_api/test_mcp_c_logging_api.cc @@ -5,10 +5,11 @@ #include #include +#include #include #include -#include #include +#include #include #include @@ -21,6 +22,18 @@ namespace mcp { namespace c_api { namespace { +// Helper functions to replace std::filesystem +namespace { +bool file_exists(const std::string& path) { + struct stat buffer; + return (stat(path.c_str(), &buffer) == 0); +} + +void remove_file(const std::string& path) { + std::remove(path.c_str()); +} +} // namespace + // Test fixture for logging API tests class LoggingApiTest : public ::testing::Test { protected: @@ -42,10 +55,10 @@ class LoggingApiTest : public ::testing::Test { void cleanupTestFiles() { // Remove test log files - std::filesystem::remove("test.log"); - std::filesystem::remove("test_rotating.log"); + remove_file("test.log"); + remove_file("test_rotating.log"); for (int i = 0; i < 10; ++i) { - std::filesystem::remove("test_rotating.log." + std::to_string(i)); + remove_file("test_rotating.log." + std::to_string(i)); } } @@ -228,8 +241,8 @@ TEST_F(LoggingApiTest, RotatingFileSink) { EXPECT_EQ(mcp_logger_flush(logger_handle), MCP_LOG_OK); // Check that rotation occurred - EXPECT_TRUE(std::filesystem::exists("test_rotating.log")); - EXPECT_TRUE(std::filesystem::exists("test_rotating.log.0")); + EXPECT_TRUE(file_exists("test_rotating.log")); + EXPECT_TRUE(file_exists("test_rotating.log.0")); mcp_logger_release(logger_handle); mcp_sink_release(sink_handle); @@ -493,7 +506,7 @@ TEST_F(LoggingApiTest, ShutdownCleanup) { mcp_sink_release(sink2); // Clean up files - std::filesystem::remove("test1.log"); + remove_file("test1.log"); } // Test error conditions From 93ea3ee1775ef1581b63a6b7d9718bb4d3c34ff6 Mon Sep 17 00:00:00 2001 From: gophergogo Date: Tue, 7 Oct 2025 09:20:33 -0700 Subject: [PATCH 33/33] make format CPP code to apply clang-format (#122) --- src/logging/logger_registry.cc | 8 ++++---- src/network/listener_impl.cc | 6 ++---- src/network/tcp_server_listener_impl.cc | 12 ++++-------- tests/c_api/test_mcp_c_logging_api.cc | 6 ++---- tests/logging/test_log_sink.cc | 6 ++---- tests/network/test_connection_utility.cc | 7 +++---- 6 files changed, 17 insertions(+), 28 deletions(-) diff --git a/src/logging/logger_registry.cc b/src/logging/logger_registry.cc index 85413700..e3b5338f 100644 --- a/src/logging/logger_registry.cc +++ b/src/logging/logger_registry.cc @@ -214,8 +214,8 @@ void LoggerRegistry::setBloomFilter(bool enabled, // Add all existing logger names for (const auto& logger_pair : loggers_) { - const auto& name = logger_pair.first; - const auto& logger = logger_pair.second; + const auto& name = logger_pair.first; + const auto& logger = logger_pair.second; bloom_filter_.add(name); logger->setBloomFilterHint(&bloom_filter_); } @@ -224,8 +224,8 @@ void LoggerRegistry::setBloomFilter(bool enabled, // Clear bloom filter hints for (auto& logger_pair : loggers_) { - auto& name = logger_pair.first; - auto& logger = logger_pair.second; + auto& name = logger_pair.first; + auto& logger = logger_pair.second; logger->setBloomFilterHint(nullptr); } } diff --git a/src/network/listener_impl.cc b/src/network/listener_impl.cc index 065d7898..0ce5e372 100644 --- a/src/network/listener_impl.cc +++ b/src/network/listener_impl.cc @@ -106,10 +106,8 @@ VoidResult ActiveListener::listen() { socket_opts.close_on_exec = true; socket_opts.reuse_address = true; // Essential for server sockets - auto socket = createListenSocket( - config_.address, - socket_opts, - config_.bind_to_port); + auto socket = + createListenSocket(config_.address, socket_opts, config_.bind_to_port); if (!socket) { Error err; diff --git a/src/network/tcp_server_listener_impl.cc b/src/network/tcp_server_listener_impl.cc index 441cd517..fb3e93e0 100644 --- a/src/network/tcp_server_listener_impl.cc +++ b/src/network/tcp_server_listener_impl.cc @@ -322,10 +322,8 @@ TcpActiveListener::TcpActiveListener(event::Dispatcher& dispatcher, socket_opts.close_on_exec = true; socket_opts.reuse_address = true; - auto socket_result = createListenSocket( - config_.address, - socket_opts, - config_.bind_to_port); + auto socket_result = + createListenSocket(config_.address, socket_opts, config_.bind_to_port); std::cerr << "[DEBUG] createListenSocket returned: " << (socket_result ? "SUCCESS" : "NULL") << std::endl; @@ -538,10 +536,8 @@ std::unique_ptr ListenerFactory::createTcpListener( socket_opts.close_on_exec = true; socket_opts.reuse_address = true; - auto socket_result = createListenSocket( - config.address, - socket_opts, - config.bind_to_port); + auto socket_result = + createListenSocket(config.address, socket_opts, config.bind_to_port); if (socket_result) { socket = std::move(socket_result); diff --git a/tests/c_api/test_mcp_c_logging_api.cc b/tests/c_api/test_mcp_c_logging_api.cc index e07c32da..66ed5b5d 100644 --- a/tests/c_api/test_mcp_c_logging_api.cc +++ b/tests/c_api/test_mcp_c_logging_api.cc @@ -9,11 +9,11 @@ #include #include #include -#include #include #include #include +#include #include "mcp/c_api/mcp_c_logging_api.h" #include "mcp/c_api/mcp_c_types.h" @@ -29,9 +29,7 @@ bool file_exists(const std::string& path) { return (stat(path.c_str(), &buffer) == 0); } -void remove_file(const std::string& path) { - std::remove(path.c_str()); -} +void remove_file(const std::string& path) { std::remove(path.c_str()); } } // namespace // Test fixture for logging API tests diff --git a/tests/logging/test_log_sink.cc b/tests/logging/test_log_sink.cc index dc180156..32fb1541 100644 --- a/tests/logging/test_log_sink.cc +++ b/tests/logging/test_log_sink.cc @@ -1,9 +1,9 @@ #include #include #include -#include #include +#include #include "mcp/logging/log_sink.h" @@ -16,9 +16,7 @@ bool file_exists(const std::string& path) { return (stat(path.c_str(), &buffer) == 0); } -void remove_file(const std::string& path) { - std::remove(path.c_str()); -} +void remove_file(const std::string& path) { std::remove(path.c_str()); } } // namespace class TestLogSink : public LogSink { diff --git a/tests/network/test_connection_utility.cc b/tests/network/test_connection_utility.cc index f2c0220a..ddee70ab 100644 --- a/tests/network/test_connection_utility.cc +++ b/tests/network/test_connection_utility.cc @@ -285,12 +285,11 @@ TEST_F(ConnectionUtilityTest, ComprehensiveSocketStateValidation) { // For boolean options on macOS, any non-zero value means enabled if (opt.level == IPPROTO_TCP && opt.optname == TCP_NODELAY) { EXPECT_NE(0, value) << "Option " << opt.name << " should be enabled"; - } else if (opt.level == SOL_SOCKET && - (opt.optname == SO_KEEPALIVE + } else if (opt.level == SOL_SOCKET && (opt.optname == SO_KEEPALIVE #ifdef SO_NOSIGPIPE - || opt.optname == SO_NOSIGPIPE + || opt.optname == SO_NOSIGPIPE #endif - )) { + )) { EXPECT_NE(0, value) << "Option " << opt.name << " should be enabled"; } else { EXPECT_EQ(opt.expected_value, value)