Fix/decode tool call (#36)

* Adding unit test

* Decode entire request to strongly typed Method call. This allows NotRequired parameters to properly decode from null, which wouldn't be possible when decoding from the 'null' JSON encoding directly.
This commit is contained in:
Adam Wulf 2025-03-31 07:34:33 -05:00 • committed by GitHub
commit 19857af5bf
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 38 additions and 6 deletions

View file

@ -161,12 +161,11 @@ final class TypedRequestHandler<M: Method>: RequestHandlerBox, @unchecked Sendab
let decoder = JSONDecoder()
// Create a concrete request from the type-erased one
let data = try encoder.encode(request.params)
let params = try decoder.decode(M.Parameters.self, from: data)
let typedRequest = Request<M>(id: request.id, method: M.name, params: params)
let data = try encoder.encode(request)
let request = try decoder.decode(Request<M>.self, from: data)
// Handle with concrete type
let response = try await _handle(typedRequest)
let response = try await _handle(request)
// Convert result to AnyMethod response
switch response.result {

View file

@ -111,7 +111,7 @@ struct ToolTests {
let emptyParams = ListTools.Parameters()
#expect(emptyParams.cursor == nil)
}
@Test("ListTools request decoding with omitted params")
func testListToolsRequestDecodingWithOmittedParams() throws {
// Test decoding when params field is omitted
@ -126,7 +126,7 @@ struct ToolTests {
#expect(decoded.id == "test-id")
#expect(decoded.method == ListTools.name)
}
@Test("ListTools request decoding with null params")
func testListToolsRequestDecodingWithNullParams() throws {
// Test decoding when params field is null
@ -205,4 +205,37 @@ struct ToolTests {
func testToolListChangedNotification() throws {
#expect(ToolListChangedNotification.name == "notifications/tools/list_changed")
}
@Test("ListTools handler invocation without params")
func testListToolsHandlerWithoutParams() async throws {
let jsonString = """
{"jsonrpc":"2.0","id":1,"method":"tools/list"}
"""
let jsonData = jsonString.data(using: .utf8)!
let anyRequest = try JSONDecoder().decode(AnyRequest.self, from: jsonData)
let handler = TypedRequestHandler<ListTools> { request in
#expect(request.method == ListTools.name)
#expect(request.id == 1)
#expect(request.params.cursor == nil)
let testTool = Tool(name: "test_tool", description: "Test tool for verification")
return ListTools.response(id: request.id, result: ListTools.Result(tools: [testTool]))
}
let response = try await handler(anyRequest)
if case .success(let value) = response.result {
let encoder = JSONEncoder()
let decoder = JSONDecoder()
let data = try encoder.encode(value)
let result = try decoder.decode(ListTools.Result.self, from: data)
#expect(result.tools.count == 1)
#expect(result.tools[0].name == "test_tool")
} else {
#expect(Bool(false), "Expected success result")
}
}
}