From fb2498f50827f0283dabc06c5a5aee0b3b3c0374 Mon Sep 17 00:00:00 2001 From: systemBlue <290303321+systemblueio@users.noreply.github.com> Date: Sun, 7 Jun 2026 11:00:49 -0400 Subject: [PATCH] fix: preserve internal error message when decoding from a peer MCPError's decoder dropped the message for code -32603 by passing nil as the detail fallback, while every other standard JSON-RPC error case falls back to the message. A peer sending {"code":-32603,"message":"..."} with no data.detail decoded to .internalError(nil), losing the message. Use the message fallback so internalError matches the other cases. --- Sources/MCP/Base/Error.swift | 2 +- Tests/MCPTests/ResponseTests.swift | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/Sources/MCP/Base/Error.swift b/Sources/MCP/Base/Error.swift index b7196f07..2d1cde75 100644 --- a/Sources/MCP/Base/Error.swift +++ b/Sources/MCP/Base/Error.swift @@ -237,7 +237,7 @@ extension MCPError: Codable { case -32602: self = .invalidParams(unwrapDetail(message)) case -32603: - self = .internalError(unwrapDetail(nil)) + self = .internalError(unwrapDetail(message)) case -32042: // Extract elicitations array from data var elicitations: [URLElicitationInfo] = [] diff --git a/Tests/MCPTests/ResponseTests.swift b/Tests/MCPTests/ResponseTests.swift index cb918521..165ede71 100644 --- a/Tests/MCPTests/ResponseTests.swift +++ b/Tests/MCPTests/ResponseTests.swift @@ -84,6 +84,29 @@ struct ResponseTests { } } + @Test("Internal error preserves the message from an external server") + func testInternalErrorPreservesMessage() throws { + // A peer sends a -32603 error with a message and no `data.detail`, like + // every other JSON-RPC error. Decoding should keep the message instead + // of dropping it, matching the other standard error cases. + let jsonString = """ + {"jsonrpc":"2.0","id":"test-id","error":{"code":-32603,"message":"Database connection failed"}} + """ + let data = jsonString.data(using: .utf8)! + + let decoder = JSONDecoder() + let decoded = try decoder.decode(Response.self, from: data) + + if case .failure(let decodedError) = decoded.result { + #expect(decodedError.code == -32603) + #expect( + decodedError.localizedDescription + == "Internal error: Database connection failed") + } else { + #expect(Bool(false), "Expected error result") + } + } + @Test("Empty result response encoding") func testEmptyResultResponseEncoding() throws { let response = EmptyMethod.response(id: "test-id")