Skip to content

Commit 76a27f2

Browse files
committed
Fix streamable HTTP integration test API usage
The test was incorrectly passing full JSON-RPC envelopes to transport.request(), which double-wrapped them. The request() method expects: - First arg: JSON-RPC method name (e.g., "initialize") - Second arg: Just the params object The method returns the unwrapped result (not full envelope). Fixed all 4 test functions to use the API correctly: - test_basic_request_response - test_session_management - test_server_info - test_error_handling Also added exceptions.hpp include for TransportError.
1 parent 7a33828 commit 76a27f2

1 file changed

Lines changed: 54 additions & 75 deletions

File tree

tests/server/streamable_http_integration.cpp

Lines changed: 54 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
/// - Simpler than SSE (no separate GET endpoint for events)
1010

1111
#include "fastmcpp/client/transports.hpp"
12+
#include "fastmcpp/exceptions.hpp"
1213
#include "fastmcpp/mcp/handler.hpp"
1314
#include "fastmcpp/server/streamable_http_server.hpp"
1415
#include "fastmcpp/tools/manager.hpp"
@@ -64,45 +65,32 @@ void test_basic_request_response()
6465
client::StreamableHttpTransport transport("http://" + host + ":" + std::to_string(port));
6566

6667
// Initialize should work and create a session
67-
Json init_request = {{"jsonrpc", "2.0"},
68-
{"id", 1},
69-
{"method", "initialize"},
70-
{"params",
71-
{{"protocolVersion", "2024-11-05"},
72-
{"capabilities", Json::object()},
73-
{"clientInfo", {{"name", "test_client"}, {"version", "1.0.0"}}}}}};
74-
75-
auto init_response = transport.request("mcp", init_request);
76-
77-
// Should have a valid response
78-
assert(init_response.contains("result") && "Initialize should return result");
79-
assert(init_response["result"].contains("serverInfo") && "Should have serverInfo");
68+
// Note: request() takes method name and params, returns unwrapped result
69+
Json init_params = {{"protocolVersion", "2024-11-05"},
70+
{"capabilities", Json::object()},
71+
{"clientInfo", {{"name", "test_client"}, {"version", "1.0.0"}}}};
72+
73+
auto init_result = transport.request("initialize", init_params);
74+
75+
// Should have a valid result (already unwrapped from JSON-RPC envelope)
76+
assert(init_result.contains("serverInfo") && "Should have serverInfo");
8077
assert(transport.has_session() && "Should have session after initialize");
8178

8279
// List tools
83-
Json list_request = {
84-
{"jsonrpc", "2.0"}, {"id", 2}, {"method", "tools/list"}, {"params", {}}};
85-
86-
auto list_response = transport.request("mcp", list_request);
87-
assert(list_response.contains("result") && "tools/list should return result");
88-
assert(list_response["result"].contains("tools") && "Should have tools array");
80+
auto list_result = transport.request("tools/list", Json::object());
81+
assert(list_result.contains("tools") && "Should have tools array");
8982

90-
auto& tools = list_response["result"]["tools"];
83+
auto& tools = list_result["tools"];
9184
assert(tools.is_array() && tools.size() == 1 && "Should have one tool");
9285
assert(tools[0]["name"] == "echo" && "Tool should be echo");
9386

9487
// Call the echo tool
95-
Json call_request = {
96-
{"jsonrpc", "2.0"},
97-
{"id", 3},
98-
{"method", "tools/call"},
99-
{"params", {{"name", "echo"}, {"arguments", {{"message", "Hello, World!"}}}}}};
88+
Json call_params = {{"name", "echo"}, {"arguments", {{"message", "Hello, World!"}}}};
10089

101-
auto call_response = transport.request("mcp", call_request);
102-
assert(call_response.contains("result") && "tools/call should return result");
103-
assert(call_response["result"].contains("content") && "Should have content");
90+
auto call_result = transport.request("tools/call", call_params);
91+
assert(call_result.contains("content") && "Should have content");
10492

105-
auto& content = call_response["result"]["content"];
93+
auto& content = call_result["content"];
10694
assert(content.is_array() && content.size() > 0 && "Should have content array");
10795
assert(content[0]["type"] == "text" && "Content should be text");
10896
assert(content[0]["text"] == "Hello, World!" && "Echo should return input");
@@ -156,16 +144,12 @@ void test_session_management()
156144
// Before initialize, should have no session
157145
assert(!transport.has_session() && "Should have no session before initialize");
158146

159-
// Initialize
160-
Json init_request = {{"jsonrpc", "2.0"},
161-
{"id", 1},
162-
{"method", "initialize"},
163-
{"params",
164-
{{"protocolVersion", "2024-11-05"},
165-
{"capabilities", Json::object()},
166-
{"clientInfo", {{"name", "test"}, {"version", "1.0"}}}}}};
147+
// Initialize - request() takes method name and params
148+
Json init_params = {{"protocolVersion", "2024-11-05"},
149+
{"capabilities", Json::object()},
150+
{"clientInfo", {{"name", "test"}, {"version", "1.0"}}}};
167151

168-
transport.request("mcp", init_request);
152+
transport.request("initialize", init_params);
169153

170154
// After initialize, should have session
171155
assert(transport.has_session() && "Should have session after initialize");
@@ -176,10 +160,7 @@ void test_session_management()
176160
assert(server.session_count() == 1 && "Server should have 1 session");
177161

178162
// Second request should reuse session
179-
Json list_request = {
180-
{"jsonrpc", "2.0"}, {"id", 2}, {"method", "tools/list"}, {"params", {}}};
181-
182-
transport.request("mcp", list_request);
163+
transport.request("tools/list", Json::object());
183164

184165
// Session ID should still be the same
185166
assert(transport.session_id() == session_id && "Session ID should persist");
@@ -228,19 +209,13 @@ void test_server_info()
228209
{
229210
client::StreamableHttpTransport transport("http://" + host + ":" + std::to_string(port));
230211

231-
Json init_request = {{"jsonrpc", "2.0"},
232-
{"id", 1},
233-
{"method", "initialize"},
234-
{"params",
235-
{{"protocolVersion", "2024-11-05"},
236-
{"capabilities", Json::object()},
237-
{"clientInfo", {{"name", "test"}, {"version", "1.0"}}}}}};
238-
239-
auto response = transport.request("mcp", init_request);
212+
Json init_params = {{"protocolVersion", "2024-11-05"},
213+
{"capabilities", Json::object()},
214+
{"clientInfo", {{"name", "test"}, {"version", "1.0"}}}};
240215

241-
assert(response.contains("result"));
242-
auto& result = response["result"];
216+
auto result = transport.request("initialize", init_params);
243217

218+
// Result is already unwrapped from JSON-RPC envelope
244219
// Check server info
245220
assert(result.contains("serverInfo"));
246221
auto& server_info = result["serverInfo"];
@@ -292,28 +267,32 @@ void test_error_handling()
292267
client::StreamableHttpTransport transport("http://" + host + ":" + std::to_string(port));
293268

294269
// Initialize first
295-
Json init_request = {{"jsonrpc", "2.0"},
296-
{"id", 1},
297-
{"method", "initialize"},
298-
{"params",
299-
{{"protocolVersion", "2024-11-05"},
300-
{"capabilities", Json::object()},
301-
{"clientInfo", {{"name", "test"}, {"version", "1.0"}}}}}};
302-
303-
transport.request("mcp", init_request);
304-
305-
// Call non-existent tool
306-
Json bad_request = {{"jsonrpc", "2.0"},
307-
{"id", 2},
308-
{"method", "tools/call"},
309-
{"params", {{"name", "nonexistent"}, {"arguments", {}}}}};
310-
311-
auto error_response = transport.request("mcp", bad_request);
312-
313-
// Should have error, not result
314-
assert(error_response.contains("error") && "Should have error response");
315-
assert(error_response["error"].contains("code") && "Error should have code");
316-
assert(error_response["error"].contains("message") && "Error should have message");
270+
Json init_params = {{"protocolVersion", "2024-11-05"},
271+
{"capabilities", Json::object()},
272+
{"clientInfo", {{"name", "test"}, {"version", "1.0"}}}};
273+
274+
transport.request("initialize", init_params);
275+
276+
// Call non-existent tool - should throw TransportError with JSON-RPC error
277+
Json bad_params = {{"name", "nonexistent"}, {"arguments", Json::object()}};
278+
279+
bool caught_error = false;
280+
try
281+
{
282+
transport.request("tools/call", bad_params);
283+
// Should not reach here
284+
assert(false && "Should have thrown error for non-existent tool");
285+
}
286+
catch (const fastmcpp::TransportError& e)
287+
{
288+
// Expected - transport throws on JSON-RPC errors
289+
std::string error_msg = e.what();
290+
assert(error_msg.find("JSON-RPC error") != std::string::npos &&
291+
"Should be JSON-RPC error");
292+
caught_error = true;
293+
}
294+
295+
assert(caught_error && "Should have caught TransportError");
317296

318297
std::cout << "PASSED\n";
319298
}

0 commit comments

Comments
 (0)