Probably a couple of concepts are mixed here. Please allow me to explain:
1) Memory *protection*: If you mean by that that certain areas of memory can be prevented from getting overwritten, yes, this is perfectly possible. If you load kickstart modules with "LoadModules", you can protect them from getting overwritten by MuProtectModules, this is what the command is good for. If you write a program and want its code segment protected from getting overwritten, you can do so by post-processing with MuLink. All the features are provided by the mmu.library back then.... of course, nobody ever used MuLink, but MuProtectModules is in active use.
2) If you mean *isolation* of programs, i.e. protect the address space of program a) from messing with the address space of program b), then there are only limited means (but *some* means) to do that, but programs need to request this explicitly. Problem: The Os moves its data structures around in global memory and has no resource management. Meaning, it has no control which process "owns" a resource. Thus, every program that interacts with the Os *necessarily* has to see parts of the global address space simply because that's where the Os keeps all its data. There is neither a problem with program a) allocating a resource, passing it over to program b) which uses it, and program c) releasing it. As long as this is consistent.
3) Can programs still isolate *parts* of their data? Yes, they can. Unfortuntely, this part of the data cannot be used to store any type of Os structures, only private data. But still. The corresponding concept is a "MMUContext", and again, it is provided by the mmu.library. A program thus can setup a context, shares parts of the global (default) context with the Os structure with other programs, but protect its private data from other programs running in other contexts. Again, the concept is there, the software that provides such magic is there (including context switches, context creation and administration) just that nobody uses it for that. Private memory is that - private. It should not have MEMF_PUBLIC set, it does not exist in exec, but the memory.library can provide such memory. The memory.library *also* exists, just no programs using it.
4) Is virtual memory possible? Not for Os structures. Only for private memory. Reasons are basically that swapping in memory requires a task switch, thus breaks any Forbid() and Disable(), and the Os is not prepared for that. However, if a program uses private memory (via the memory.library) such memory *can* be swapped out, and loaded from disk (automatically), again - of course - breaking the Forbid() state. Just that there are no programs using the mechanism. Thus, a lot of plans and a lot of mechanisms have been created, but since the software basis and the user basis broke away, all the mechanisms and constructions remained unused.