Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 18 additions & 17 deletions internal/mcp/connection.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,16 @@ func parseSSEResponse(body []byte) ([]byte, error) {
// - error: Detailed parsing error with body preview on failure
func parseJSONRPCResponseWithSSE(body []byte, statusCode int, contextDesc string) (*Response, error) {
var rpcResponse Response
httpErrorResponse := func() *Response {
return &Response{
JSONRPC: "2.0",
Error: &ResponseError{
Code: -32603, // Internal error
Message: fmt.Sprintf("HTTP %d: %s", statusCode, http.StatusText(statusCode)),
Data: json.RawMessage(body),
},
}
}

// Try parsing as standard JSON first
if err := json.Unmarshal(body, &rpcResponse); err != nil {
Expand All @@ -80,21 +90,14 @@ func parseJSONRPCResponseWithSSE(body []byte, statusCode int, contextDesc string
// construct a JSON-RPC error response with HTTP error details
if statusCode != http.StatusOK {
logConn.Printf("HTTP error status=%d, body cannot be parsed as JSON-RPC", statusCode)
return &Response{
JSONRPC: "2.0",
Error: &ResponseError{
Code: -32603, // Internal error
Message: fmt.Sprintf("HTTP %d: %s", statusCode, http.StatusText(statusCode)),
Data: json.RawMessage(body),
},
}, nil
return httpErrorResponse(), nil
}
// Include the response body to help debug what the server actually returned
bodyPreview := string(body)
if len(bodyPreview) > 500 {
bodyPreview = bodyPreview[:500] + "... (truncated)"
}
return nil, fmt.Errorf("failed to parse %s (received non-JSON or malformed response): %w\nResponse body: %s", contextDesc, err, bodyPreview)
return nil, fmt.Errorf("failed to parse %s (received non-JSON or malformed response): %w\nResponse body: %s", contextDesc, sseErr, bodyPreview)
}

// Successfully extracted JSON from SSE, now parse it
Expand All @@ -103,20 +106,18 @@ func parseJSONRPCResponseWithSSE(body []byte, statusCode int, contextDesc string
// construct a JSON-RPC error response with HTTP error details
if statusCode != http.StatusOK {
logConn.Printf("HTTP error status=%d, SSE data cannot be parsed as JSON-RPC", statusCode)
return &Response{
JSONRPC: "2.0",
Error: &ResponseError{
Code: -32603, // Internal error
Message: fmt.Sprintf("HTTP %d: %s", statusCode, http.StatusText(statusCode)),
Data: json.RawMessage(body),
},
}, nil
return httpErrorResponse(), nil
}
return nil, fmt.Errorf("failed to parse JSON data extracted from SSE response: %w\nJSON data: %s", err, string(sseData))
}
logConn.Printf("Successfully parsed SSE-formatted response")
}

if statusCode != http.StatusOK {
logConn.Printf("HTTP error status=%d, returning synthetic JSON-RPC error response", statusCode)
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The unconditional non-200 handling at the end returns a synthetic JSON-RPC error even when the body was successfully parsed as a valid JSON-RPC response. This discards backend-provided JSON-RPC errors (code/message/data) and conflicts with sendHTTPRequest()’s documented behavior of passing through valid JSON-RPC on HTTP error statuses. Consider removing this final statusCode check, or only synthesizing an error when the parsed response is not a valid JSON-RPC response (e.g., missing jsonrpc/id and no error), and otherwise return the parsed rpcResponse unchanged.

Suggested change
logConn.Printf("HTTP error status=%d, returning synthetic JSON-RPC error response", statusCode)
// If we successfully parsed what looks like a JSON-RPC response, prefer the
// backend-provided payload (including any error object) over a synthetic one.
if rpcResponse.JSONRPC != "" || rpcResponse.Error != nil {
logConn.Printf("HTTP error status=%d, but response contains JSON-RPC payload; returning backend response", statusCode)
return &rpcResponse, nil
}
logConn.Printf("HTTP error status=%d with no valid JSON-RPC payload, returning synthetic JSON-RPC error response", statusCode)

Copilot uses AI. Check for mistakes.
return httpErrorResponse(), nil
}

return &rpcResponse, nil
}

Expand Down