Ok, why the two SETs?
You can't SET an index to ZERO.
So, what some people do to get around this, is SET the index to 1. Then SET the index DOWN BY 1.
Why do you get that hex value?
Firstly, "when the first "set" completed, the value of MP-MESSAGE-IX is 1" is not correct. It is zero.
An index is always a displacement from the start of the OCCURS. Entry one in the OCCURS is displacement zero. That will be the value of the index when you SET it to 1 (because you want the first entry in the table).
This leads to why you can't SET to ZERO. The "zeorth" entry in a table is the -1 entry. Doesn't exist, and if you ever use that index value you'll have a problem. If using SSRANGE you'll set off the trap. If not, you'll be using invalid data which, if you're lucky, will abend, if you're unlucky will be merrily used until you or someone else spots it, hopefully in unit-testing
The third question, which you didn't ask, is "is this a good way to do it"? And the answer is "no".
It is confusing, as you have discovered. It is error-prone in that you always have to treat those two SETs as one, but someone is going to come along and not do that.
If you show some code relating to any "looping" constructs that you have, we can make suggestions of how it could be coded to be less problematic.