unsigned int n = obj is not an assignment expression, it doesn't use any assignment, built-in or overloaded.
It is initialization and that simply initializes the object by performing overload resolution on the conversion functions in MyClass, choosing the best matching one for the type that is supposed to be initialized.
obj == 0 is however an expression and overload resolution is applied for operator== (not conversion functions!) in order to determine whether == should be interpreted as built-in comparison operator or whether it should call a operator== overload defined somewhere.
In this overload resolution the built-in operator == is represented by some imagined overload declarations
bool operator==(L, R);
for every pair of types L and R where each is either a floating point type or a promoted integral type. (And then there are further such overloads for enumeration types, pointer types, pointer-to-member types, etc., which don't matter here.)
In particular there are then candidates
bool operator==(int, int);
and
bool operator==(unsigned int, int);
Both of these are viable via user-defined conversion using the MyClass conversion functions (and neither requires any further conversion of the return value). So they have the exact same implicit conversion rank each on both of the arguments.
There is no tie-breaker in overload resolution that would disambiguate one of these candidates as better than the other and therefore overload resolution is ambiguous.
In fact, if different conversion functions are used for the implicit conversion sequence on an argument by different candidates, then the two implicit conversion sequences are always considered ambiguous, regardless of whether there is any further conversion required.
const noexcept