diff --git a/source/RobotAPI/components/armem/MemoryNameSystem/CMakeLists.txt b/source/RobotAPI/components/armem/MemoryNameSystem/CMakeLists.txt
index 75a50c54304d11e5452f1e4d1f8287a65fd0e9f6..fa06c3e77bf057e9ca37e790f908e981db1147af 100644
--- a/source/RobotAPI/components/armem/MemoryNameSystem/CMakeLists.txt
+++ b/source/RobotAPI/components/armem/MemoryNameSystem/CMakeLists.txt
@@ -19,4 +19,6 @@ set(HEADERS
 armarx_add_component("${SOURCES}" "${HEADERS}")
 
 #generate the application
-armarx_generate_and_add_component_executable()
+armarx_generate_and_add_component_executable(
+    COMPONENT_NAMESPACE "armarx::armem"
+)
diff --git a/source/RobotAPI/components/armem/MemoryNameSystem/MemoryNameSystem.cpp b/source/RobotAPI/components/armem/MemoryNameSystem/MemoryNameSystem.cpp
index 47131a79a44f25dabc1e3364fcc7d3d044b3e506..0ebd0eac1dad18f7c53374c4a4fcc5ba173bbf14 100644
--- a/source/RobotAPI/components/armem/MemoryNameSystem/MemoryNameSystem.cpp
+++ b/source/RobotAPI/components/armem/MemoryNameSystem/MemoryNameSystem.cpp
@@ -29,16 +29,12 @@
 #include <RobotAPI/libraries/armem/core/error.h>
 
 
-namespace armarx
+namespace armarx::armem
 {
-    MemoryNameSystemPropertyDefinitions::MemoryNameSystemPropertyDefinitions(std::string prefix) :
-        armarx::ComponentPropertyDefinitions(prefix)
-    {
-    }
 
     armarx::PropertyDefinitionsPtr MemoryNameSystem::createPropertyDefinitions()
     {
-        armarx::PropertyDefinitionsPtr defs = new MemoryNameSystemPropertyDefinitions(getConfigIdentifier());
+        armarx::PropertyDefinitionsPtr defs = new ComponentPropertyDefinitions(getConfigIdentifier());
 
         return defs;
     }
@@ -58,7 +54,7 @@ namespace armarx
 
     void MemoryNameSystem::onConnectComponent()
     {
-        RemoteGui__createTab();
+        createRemoteGuiTab();
         RemoteGui_startRunningTask();
     }
 
@@ -73,19 +69,19 @@ namespace armarx
     }
 
 
-    armem::data::RegisterMemoryResult MemoryNameSystem::registerMemory(
-        const armem::data::RegisterMemoryInput& input, const Ice::Current& c)
+    mns::dto::RegisterServerResult MemoryNameSystem::registerServer(
+        const mns::dto::RegisterServerInput& input, const Ice::Current& c)
     {
-        armem::data::RegisterMemoryResult result = Plugin::registerMemory(input, c);
+        mns::dto::RegisterServerResult result = PluginUser::registerServer(input, c);
         tab.rebuild = true;
         return result;
     }
 
 
-    armem::data::RemoveMemoryResult MemoryNameSystem::removeMemory(
-        const armem::data::RemoveMemoryInput& input, const Ice::Current& c)
+    mns::dto::RemoveServerResult MemoryNameSystem::removeServer(
+        const mns::dto::RemoveServerInput& input, const Ice::Current& c)
     {
-        armem::data::RemoveMemoryResult result = Plugin::removeMemory(input, c);
+        mns::dto::RemoveServerResult result = PluginUser::removeServer(input, c);
         tab.rebuild = true;
         return result;
     }
@@ -94,12 +90,12 @@ namespace armarx
 
     // REMOTE GUI
 
-    void MemoryNameSystem::RemoteGui__createTab()
+    void MemoryNameSystem::createRemoteGuiTab()
     {
         using namespace armarx::RemoteGui::Client;
 
         std::scoped_lock lock(mnsMutex);
-        GridLayout grid = mns.RemoteGui_buildInfoGrid();
+        GridLayout grid = mns().RemoteGui_buildInfoGrid();
 
         VBoxLayout root = {grid, VSpacer()};
         RemoteGui_createTab(getName(), root, &tab);
@@ -110,7 +106,7 @@ namespace armarx
     {
         if (tab.rebuild.exchange(false))
         {
-            RemoteGui__createTab();
+            createRemoteGuiTab();
         }
     }
 
diff --git a/source/RobotAPI/components/armem/MemoryNameSystem/MemoryNameSystem.h b/source/RobotAPI/components/armem/MemoryNameSystem/MemoryNameSystem.h
index 795aecc66f96423aa29b28660694e09ea50a1426..f0279f4a1103a6b6f5a88f4b31ab5692cc5bda74 100644
--- a/source/RobotAPI/components/armem/MemoryNameSystem/MemoryNameSystem.h
+++ b/source/RobotAPI/components/armem/MemoryNameSystem/MemoryNameSystem.h
@@ -22,33 +22,16 @@
 
 #pragma once
 
-#include <mutex>
-
-#include <ArmarXCore/core/Component.h>
+#include <RobotAPI/libraries/armem/mns/plugins/PluginUser.h>
+#include <RobotAPI/interface/armem/mns/MemoryNameSystemInterface.h>
 
 #include <ArmarXGui/libraries/ArmarXGuiComponentPlugins/LightweightRemoteGuiComponentPlugin.h>
-// #include <RobotAPI/libraries/RobotAPIComponentPlugins/ArVizComponentPlugin.h>
 
-#include <RobotAPI/interface/armem/mns/MemoryNameSystemInterface.h>
-
-#include <RobotAPI/libraries/armem/mns/ComponentPlugin.h>
+#include <ArmarXCore/core/Component.h>
 
 
-namespace armarx
+namespace armarx::armem
 {
-    /**
-     * @class MemoryNameSystemPropertyDefinitions
-     * @brief Property definitions of `MemoryNameSystem`.
-     */
-    class MemoryNameSystemPropertyDefinitions :
-        public armarx::ComponentPropertyDefinitions
-    {
-    public:
-        MemoryNameSystemPropertyDefinitions(std::string prefix);
-    };
-
-
-
     /**
      * @defgroup Component-MemoryNameSystem MemoryNameSystem
      * @ingroup RobotAPI-Components
@@ -62,11 +45,9 @@ namespace armarx
      */
     class MemoryNameSystem :
         virtual public armarx::Component
-        , virtual public armem::mns::ComponentPluginUser
+        , virtual public armem::mns::plugins::PluginUser
         , virtual public LightweightRemoteGuiComponentPluginUser
-    //  , virtual public armarx::ArVizComponentPluginUser
     {
-        using Plugin = ComponentPluginUser;
     public:
 
         /// @see armarx::ManagedIceObject::getDefaultName()
@@ -75,20 +56,23 @@ namespace armarx
 
         // mns::MemoryNameSystemInterface interface
     public:
-        armem::data::RegisterMemoryResult registerMemory(const armem::data::RegisterMemoryInput& input, const Ice::Current&) override;
-        armem::data::RemoveMemoryResult removeMemory(const armem::data::RemoveMemoryInput& input, const Ice::Current&) override;
+        mns::dto::RegisterServerResult registerServer(const mns::dto::RegisterServerInput& input, const Ice::Current&) override;
+        mns::dto::RemoveServerResult removeServer(const mns::dto::RemoveServerInput& input, const Ice::Current&) override;
         // Others are inherited from ComponentPluginUser
 
 
         // LightweightRemoteGuiComponentPluginUser interface
     public:
 
-        void RemoteGui__createTab();
+        void createRemoteGuiTab();
         void RemoteGui_update() override;
 
 
     protected:
 
+        /// @see PropertyUser::createPropertyDefinitions()
+        armarx::PropertyDefinitionsPtr createPropertyDefinitions() override;
+
         /// @see armarx::ManagedIceObject::onInitComponent()
         void onInitComponent() override;
 
@@ -101,17 +85,13 @@ namespace armarx
         /// @see armarx::ManagedIceObject::onExitComponent()
         void onExitComponent() override;
 
-        /// @see PropertyUser::createPropertyDefinitions()
-        armarx::PropertyDefinitionsPtr createPropertyDefinitions() override;
-
 
     private:
 
         struct Properties
         {
-
         };
-        Properties p;
+        Properties properties;
 
 
         struct RemoteGuiTab : RemoteGui::Client::Tab
diff --git a/source/RobotAPI/interface/armem/mns/MemoryNameSystemInterface.ice b/source/RobotAPI/interface/armem/mns/MemoryNameSystemInterface.ice
index 85a862f4cd815168d6163d2d085426d71b298068..95b6a9fa6b03d8f7d4644d2538ecfd64d5258229 100644
--- a/source/RobotAPI/interface/armem/mns/MemoryNameSystemInterface.ice
+++ b/source/RobotAPI/interface/armem/mns/MemoryNameSystemInterface.ice
@@ -1,87 +1,116 @@
 #pragma once
 
-#include <RobotAPI/interface/armem/server/MemoryInterface.ice>
+#include <RobotAPI/interface/armem/server/ReadingMemoryInterface.ice>
+#include <RobotAPI/interface/armem/server/WritingMemoryInterface.ice>
 
 
 module armarx
 {
     module armem
     {
-        module data
+        module mns
         {
-            struct RegisterMemoryInput
-            {
-                string name;
-                server::MemoryInterface* proxy;
-
-                bool existOk = true;
-            };
-            struct RegisterMemoryResult
-            {
-                bool success;
-                string errorMessage;
-            };
-
-            struct RemoveMemoryInput
-            {
-                string name;
-                bool notExistOk = true;
-            };
-            struct RemoveMemoryResult
-            {
-                bool success;
-                string errorMessage;
-            };
-
-            dictionary<string, server::MemoryInterface*> MemoryInterfaces;
-            struct GetAllRegisteredMemoriesResult
-            {
-                bool success;
-                string errorMessage;
-
-                MemoryInterfaces proxies;
-            };
-
-            struct ResolveMemoryNameInput
-            {
-                string name;
-            };
-            struct ResolveMemoryNameResult
-            {
-                bool success;
-                string errorMessage;
-
-                server::MemoryInterface* proxy;
-            };
-
-            struct WaitForMemoryInput
-            {
-                /// The memory name.
-                string name;
-                /// Negative for no timeout.
-                long timeoutMilliSeconds = -1;
-            };
-            struct WaitForMemoryResult
+            module dto
             {
-                bool success;
-                string errorMessage;
-
-                server::MemoryInterface* proxy;
+                /**
+                 * A memory server can implement the reading and/or writing
+                 * memory interface. They should be handled individually.
+                 */
+                struct MemoryServerInterfaces
+                {
+                    server::ReadingMemoryInterface* reading;
+                    server::WritingMemoryInterface* writing;
+                };
+                dictionary<string, MemoryServerInterfaces> MemoryServerInterfacesMap;
+
+
+                /**
+                 * @brief Register a memory server.
+                 */
+                struct RegisterServerInput
+                {
+                    string name;
+                    MemoryServerInterfaces server;
+
+                    bool existOk = true;
+                };
+                struct RegisterServerResult
+                {
+                    bool success;
+                    string errorMessage;
+                };
+
+
+                /**
+                 * @brief Remove a memory server.
+                 */
+                struct RemoveServerInput
+                {
+                    string name;
+                    bool notExistOk = true;
+                };
+                struct RemoveServerResult
+                {
+                    bool success;
+                    string errorMessage;
+                };
+
+                /**
+                 * @brief Resolve a memory name.
+                 */
+                struct ResolveServerInput
+                {
+                    string name;
+                };
+                struct ResolveServerResult
+                {
+                    bool success;
+                    string errorMessage;
+
+                    MemoryServerInterfaces server;
+                };
+
+
+                /**
+                 * @brief Get all registered entries.
+                 */
+                struct GetAllRegisteredServersResult
+                {
+                    bool success;
+                    string errorMessage;
+
+                    MemoryServerInterfacesMap servers;
+                };
+
+
+                /**
+                 * @brief Wait until a server is registered.
+                 */
+                struct WaitForServerInput
+                {
+                    string name;
+                };
+                struct WaitForServerResult
+                {
+                    bool success;
+                    string errorMessage;
+
+                    MemoryServerInterfaces server;
+                };
             };
-        };
 
 
-        module mns
-        {
             interface MemoryNameSystemInterface
             {
-                data::RegisterMemoryResult registerMemory(data::RegisterMemoryInput input);
-                data::RemoveMemoryResult removeMemory(data::RemoveMemoryInput input);
+                dto::RegisterServerResult registerServer(dto::RegisterServerInput input);
+                dto::RemoveServerResult removeServer(dto::RemoveServerInput input);
+
+                dto::GetAllRegisteredServersResult getAllRegisteredServers();
 
-                data::GetAllRegisteredMemoriesResult getAllRegisteredMemories();
+                dto::ResolveServerResult resolveServer(dto::ResolveServerInput input);
 
-                data::ResolveMemoryNameResult resolveMemoryName(data::ResolveMemoryNameInput input);
-                data::WaitForMemoryResult waitForMemory(data::WaitForMemoryInput input);
+                ["amd"]  // Asynchronous Method Dispatch
+                dto::WaitForServerResult waitForServer(dto::WaitForServerInput input);
             };
         }
 
diff --git a/source/RobotAPI/libraries/armem/CMakeLists.txt b/source/RobotAPI/libraries/armem/CMakeLists.txt
index e6c3f1a8533c15e1b20a71c34e741bebcb50d12f..32c3b9b949577ab7f91b4993c186f181151abc6d 100644
--- a/source/RobotAPI/libraries/armem/CMakeLists.txt
+++ b/source/RobotAPI/libraries/armem/CMakeLists.txt
@@ -103,7 +103,9 @@ set(LIB_FILES
     server/query_proc/wm.cpp
 
     mns/MemoryNameSystem.cpp
-    mns/ComponentPlugin.cpp
+    mns/Registry.cpp
+    mns/plugins/Plugin.cpp
+    mns/plugins/PluginUser.cpp
 
     util/util.cpp
 )
@@ -210,7 +212,9 @@ set(LIB_HEADERS
 
     mns.h
     mns/MemoryNameSystem.h
-    mns/ComponentPlugin.h
+    mns/Registry.h
+    mns/plugins/Plugin.h
+    mns/plugins/PluginUser.h
 
     util/util.h
 )
diff --git a/source/RobotAPI/libraries/armem/client/MemoryNameSystem.cpp b/source/RobotAPI/libraries/armem/client/MemoryNameSystem.cpp
index 79140344ee99a143e29bcc655d6e1ed23d77b041..4dcb3d624e42b901fe0d70d91a89c136ff1692ba 100644
--- a/source/RobotAPI/libraries/armem/client/MemoryNameSystem.cpp
+++ b/source/RobotAPI/libraries/armem/client/MemoryNameSystem.cpp
@@ -27,10 +27,10 @@ namespace armarx::armem::client
     {
         ARMARX_CHECK_NOT_NULL(mns);
 
-        data::GetAllRegisteredMemoriesResult result;
+        mns::dto::GetAllRegisteredServersResult result;
         try
         {
-            result = mns->getAllRegisteredMemories();
+            result = mns->getAllRegisteredServers();
         }
         catch (const Ice::NotRegisteredException& e)
         {
@@ -39,24 +39,32 @@ namespace armarx::armem::client
 
         if (result.success)
         {
-            for (const auto& [name, proxy] : result.proxies)
+            for (const auto& [name, server] : result.servers)
             {
-                auto [it, inserted] = servers.try_emplace(name, proxy);
-                // inserted: OK
-                if (not inserted)
+                auto [it, inserted] = servers.try_emplace(name, server);
+                if (inserted)
+                {
+                    // OK
+                }
+                else
                 {
                     // Compare ice identities, update if it changed.
-                    if (it->second->ice_getIdentity() != proxy->ice_getIdentity())
+                    auto foo = [](auto & oldProxy, const auto & newProxy)
                     {
-                        // Replace old proxy by new one.
-                        it->second = proxy;
-                    }
+                        if (oldProxy->ice_getIdentity() != newProxy->ice_getIdentity())
+                        {
+                            // Replace old proxy by new one.
+                            oldProxy = newProxy;
+                        }
+                    };
+                    foo(it->second.reading, server.reading);
+                    foo(it->second.writing, server.writing);
                 }
             }
             // Remove all entries which are not there anymore.
             for (auto it = servers.begin(); it != servers.end();)
             {
-                if (result.proxies.count(it->first) == 0)
+                if (result.servers.count(it->first) == 0)
                 {
                     it = servers.erase(it);
                 }
@@ -73,7 +81,8 @@ namespace armarx::armem::client
     }
 
 
-    server::MemoryInterfacePrx MemoryNameSystem::resolveServer(const MemoryID& memoryID)
+    mns::dto::MemoryServerInterfaces
+    MemoryNameSystem::resolveServer(const MemoryID& memoryID)
     {
         if (auto it = servers.find(memoryID.memoryName); it != servers.end())
         {
@@ -94,7 +103,7 @@ namespace armarx::armem::client
     }
 
 
-    server::MemoryInterfacePrx MemoryNameSystem::waitForServer(const MemoryID& memoryID, Time timeout)
+    mns::dto::MemoryServerInterfaces MemoryNameSystem::waitForServer(const MemoryID& memoryID)
     {
         if (auto it = servers.find(memoryID.memoryName); it != servers.end())
         {
@@ -102,15 +111,14 @@ namespace armarx::armem::client
         }
         else
         {
-            armem::data::WaitForMemoryInput input;
+            mns::dto::WaitForServerInput input;
             input.name = memoryID.memoryName;
-            input.timeoutMilliSeconds = timeout.toMilliSeconds();
 
             ARMARX_CHECK_NOT_NULL(mns);
-            armem::data::WaitForMemoryResult result = mns->waitForMemory(input);
+            mns::dto::WaitForServerResult result = mns->waitForServer(input);
             if (result.success)
             {
-                return result.proxy;
+                return result.server;
             }
             else
             {
@@ -119,7 +127,7 @@ namespace armarx::armem::client
         }
     }
 
-    server::MemoryInterfacePrx MemoryNameSystem::useServer(const MemoryID& memoryID)
+    mns::dto::MemoryServerInterfaces MemoryNameSystem::useServer(const MemoryID& memoryID)
     {
         ARMARX_CHECK_NOT_NULL(component)
                 << "Owning component not set when using a memory server. \n"
@@ -131,22 +139,22 @@ namespace armarx::armem::client
     }
 
 
-    server::MemoryInterfacePrx MemoryNameSystem::useServer(const MemoryID& memoryID, ManagedIceObject& component)
+    mns::dto::MemoryServerInterfaces MemoryNameSystem::useServer(const MemoryID& memoryID, ManagedIceObject& component)
     {
-        server::MemoryInterfacePrx server = waitForServer(memoryID);
+        mns::dto::MemoryServerInterfaces server = waitForServer(memoryID);
         // Add dependency.
-        component.usingProxy(server->ice_getIdentity().name);
+        component.usingProxy(server.reading->ice_getIdentity().name);
         return server;
     }
 
 
-    server::MemoryInterfacePrx MemoryNameSystem::useServer(const std::string& memoryName)
+    mns::dto::MemoryServerInterfaces MemoryNameSystem::useServer(const std::string& memoryName)
     {
         return useServer(MemoryID().withMemoryName(memoryName));
     }
 
 
-    server::MemoryInterfacePrx MemoryNameSystem::useServer(const std::string& memoryName, ManagedIceObject& component)
+    mns::dto::MemoryServerInterfaces MemoryNameSystem::useServer(const std::string& memoryName, ManagedIceObject& component)
     {
         return useServer(MemoryID().withMemoryName(memoryName), component);
     }
@@ -154,19 +162,19 @@ namespace armarx::armem::client
 
     Reader MemoryNameSystem::getReader(const MemoryID& memoryID)
     {
-        return Reader(resolveServer(memoryID));
+        return Reader(resolveServer(memoryID).reading);
     }
 
 
     Reader MemoryNameSystem::useReader(const MemoryID& memoryID)
     {
-        return Reader(useServer(memoryID));
+        return Reader(useServer(memoryID).reading);
     }
 
 
     Reader MemoryNameSystem::useReader(const MemoryID& memoryID, ManagedIceObject& component)
     {
-        return Reader(useServer(memoryID, component));
+        return Reader(useServer(memoryID, component).reading);
     }
 
 
@@ -183,55 +191,50 @@ namespace armarx::armem::client
 
 
     template <class ClientT>
-    std::map<std::string, ClientT> MemoryNameSystem::_getAllClients() const
+    std::map<std::string, ClientT>
+    MemoryNameSystem::_getAllClients(auto&& getProxyFn) const
     {
         std::map<std::string, ClientT> result;
         for (const auto& [name, server] : servers)
         {
-            result[name] = ClientT(server);
+            result[name] = ClientT(getProxyFn(server));
         }
         return result;
     }
 
 
-    template <class ClientT>
-    std::map<std::string, ClientT> MemoryNameSystem::_getAllClients(bool update)
+
+    std::map<std::string, Reader> MemoryNameSystem::getAllReaders(bool update)
     {
         if (update)
         {
             this->update();
         }
-        return const_cast<const MemoryNameSystem&>(*this)._getAllClients<ClientT>();
-    }
-
-
-    std::map<std::string, Reader> MemoryNameSystem::getAllReaders(bool update)
-    {
-        return _getAllClients<Reader>(update);
+        return _getAllClients<Reader>(&mns::getReadingInterface);
     }
 
 
     std::map<std::string, Reader> MemoryNameSystem::getAllReaders() const
     {
-        return _getAllClients<Reader>();
+        return _getAllClients<Reader>(&mns::getReadingInterface);
     }
 
 
     Writer MemoryNameSystem::getWriter(const MemoryID& memoryID)
     {
-        return Writer(resolveServer(memoryID));
+        return Writer(resolveServer(memoryID).writing);
     }
 
 
     Writer MemoryNameSystem::useWriter(const MemoryID& memoryID)
     {
-        return Writer(useServer(memoryID));
+        return Writer(useServer(memoryID).writing);
     }
 
 
     Writer MemoryNameSystem::useWriter(const MemoryID& memoryID, ManagedIceObject& component)
     {
-        return Writer(useServer(memoryID, component));
+        return Writer(useServer(memoryID, component).writing);
     }
 
 
@@ -249,13 +252,17 @@ namespace armarx::armem::client
 
     std::map<std::string, Writer> MemoryNameSystem::getAllWriters(bool update)
     {
-        return _getAllClients<Writer>(update);
+        if (update)
+        {
+            this->update();
+        }
+        return _getAllClients<Writer>(&mns::getWritingInterface);
     }
 
 
     std::map<std::string, Writer> MemoryNameSystem::getAllWriters() const
     {
-        return _getAllClients<Writer>();
+        return _getAllClients<Writer>(&mns::getWritingInterface);
     }
 
 
@@ -341,15 +348,15 @@ namespace armarx::armem::client
     }
 
 
-    void MemoryNameSystem::registerServer(const MemoryID& memoryID, server::MemoryInterfacePrx proxy)
+    void MemoryNameSystem::registerServer(const MemoryID& memoryID, mns::dto::MemoryServerInterfaces server)
     {
-        data::RegisterMemoryInput input;
+        mns::dto::RegisterServerInput input;
         input.name = memoryID.memoryName;
-        input.proxy = proxy;
-        ARMARX_CHECK_NOT_NULL(input.proxy);
+        input.server = server;
+        ARMARX_CHECK(server.reading or server.writing) << VAROUT(server.reading) << " | " << VAROUT(server.writing);
 
         ARMARX_CHECK_NOT_NULL(mns);
-        data::RegisterMemoryResult result = mns->registerMemory(input);
+        mns::dto::RegisterServerResult result = mns->registerServer(input);
         if (!result.success)
         {
             throw error::ServerRegistrationOrRemovalFailed("register", memoryID, result.errorMessage);
@@ -359,11 +366,11 @@ namespace armarx::armem::client
 
     void MemoryNameSystem::removeServer(const MemoryID& memoryID)
     {
-        data::RemoveMemoryInput input;
+        mns::dto::RemoveServerInput input;
         input.name = memoryID.memoryName;
 
         ARMARX_CHECK_NOT_NULL(mns);
-        data::RemoveMemoryResult result = mns->removeMemory(input);
+        mns::dto::RemoveServerResult result = mns->removeServer(input);
         if (!result.success)
         {
             throw error::ServerRegistrationOrRemovalFailed("remove", memoryID, result.errorMessage);
diff --git a/source/RobotAPI/libraries/armem/client/MemoryNameSystem.h b/source/RobotAPI/libraries/armem/client/MemoryNameSystem.h
index d981bab0383f0d04fdc221fbbd2cbd062d061c53..7779ca2d8b1a65b07ef446675685695dc243de58 100644
--- a/source/RobotAPI/libraries/armem/client/MemoryNameSystem.h
+++ b/source/RobotAPI/libraries/armem/client/MemoryNameSystem.h
@@ -30,6 +30,7 @@
 
 #include <RobotAPI/libraries/armem/core/MemoryID.h>
 #include <RobotAPI/libraries/armem/client/util/MemoryListener.h>
+#include <RobotAPI/libraries/armem/mns/Registry.h>
 
 
 namespace armarx
@@ -97,41 +98,6 @@ namespace armarx::armem::client
          */
         void update();
 
-        /**
-         * @brief Resolve the given memory server for the given memory ID.
-         *
-         * @param memoryID The memory ID.
-         * @return The memory server proxy.
-         *
-         * @throw `error::CouldNotResolveMemoryServer` If the memory name could not be resolved.
-         */
-        server::MemoryInterfacePrx resolveServer(const MemoryID& memoryID);
-
-        /**
-         * @brief Wait for the given memory server.
-         *
-         * @param memoryID The memory ID.
-         * @param timeout How long to wait at maximum. Negative values indicate infinite wait.
-         * @return The memory server proxy.
-         *
-         * @throw `error::CouldNotResolveMemoryServer` If the memory name could not be resolved.
-         */
-        server::MemoryInterfacePrx waitForServer(const MemoryID& memoryID, Time timeout = Time::milliSeconds(-1));
-
-        /**
-        * @brief Wait for the given memory server and add a dependency to the memory server.
-        *
-        * @param memoryID The memory ID.
-        * @param component The component that should depend on the memory server.
-        * @return The memory server proxy.
-        *
-        * @throw `error::CouldNotResolveMemoryServer` If the memory name could not be resolved.
-        */
-        server::MemoryInterfacePrx useServer(const MemoryID& memoryID);
-        server::MemoryInterfacePrx useServer(const MemoryID& memoryID, ManagedIceObject& component);
-        server::MemoryInterfacePrx useServer(const std::string& memoryName);
-        server::MemoryInterfacePrx useServer(const std::string& memoryName, ManagedIceObject& component);
-
 
         // Reader/Writer construction
 
@@ -225,7 +191,7 @@ namespace armarx::armem::client
          *
          * @throw `error::ServerRegistrationOrRemovalFailed` If the registration failed.
          */
-        void registerServer(const MemoryID& memoryID, server::MemoryInterfacePrx server);
+        void registerServer(const MemoryID& memoryID, mns::dto::MemoryServerInterfaces server);
 
         /**
          * @brief Remove a memory server from the MNS.
@@ -247,12 +213,47 @@ namespace armarx::armem::client
         }
 
 
+    private:
+
+        /**
+         * @brief Resolve the given memory server for the given memory ID.
+         *
+         * @param memoryID The memory ID.
+         * @return The memory server proxy.
+         *
+         * @throw `error::CouldNotResolveMemoryServer` If the memory name could not be resolved.
+         */
+        mns::dto::MemoryServerInterfaces resolveServer(const MemoryID& memoryID);
+
+        /**
+         * @brief Wait for the given memory server.
+         *
+         * @param memoryID The memory ID.
+         * @return The memory server proxy.
+         *
+         * @throw `error::CouldNotResolveMemoryServer` If the memory name could not be resolved.
+         */
+        mns::dto::MemoryServerInterfaces waitForServer(const MemoryID& memoryID);
+
+        /**
+        * @brief Wait for the given memory server and add a dependency to the memory server.
+        *
+        * @param memoryID The memory ID.
+        * @param component The component that should depend on the memory server.
+        * @return The memory server proxy.
+        *
+        * @throw `error::CouldNotResolveMemoryServer` If the memory name could not be resolved.
+        */
+        mns::dto::MemoryServerInterfaces useServer(const MemoryID& memoryID);
+        mns::dto::MemoryServerInterfaces useServer(const MemoryID& memoryID, ManagedIceObject& component);
+        mns::dto::MemoryServerInterfaces useServer(const std::string& memoryName);
+        mns::dto::MemoryServerInterfaces useServer(const std::string& memoryName, ManagedIceObject& component);
+
+
     private:
 
         template <class ClientT>
-        std::map<std::string, ClientT> _getAllClients(bool update);
-        template <class ClientT>
-        std::map<std::string, ClientT> _getAllClients() const;
+        std::map<std::string, ClientT> _getAllClients(auto&& proxyFn) const;
 
 
         /// The MNS proxy.
@@ -262,7 +263,7 @@ namespace armarx::armem::client
         ManagedIceObject* component = nullptr;
 
         /// The registered memory servers.
-        std::map<std::string, server::MemoryInterfacePrx> servers;
+        std::map<std::string, mns::dto::MemoryServerInterfaces> servers;
 
     };
 
diff --git a/source/RobotAPI/libraries/armem/mns/ComponentPlugin.cpp b/source/RobotAPI/libraries/armem/mns/ComponentPlugin.cpp
deleted file mode 100644
index 79e58300a6968dfda3f60d89ff0511f9ec72f267..0000000000000000000000000000000000000000
--- a/source/RobotAPI/libraries/armem/mns/ComponentPlugin.cpp
+++ /dev/null
@@ -1,63 +0,0 @@
-#include "ComponentPlugin.h"
-
-#include <ArmarXCore/core/exceptions/local/ExpressionException.h>
-#include <ArmarXCore/core/time/CycleUtil.h>
-
-#include "../error.h"
-
-
-namespace armarx::armem::mns::plugins
-{
-
-}
-
-
-namespace armarx::armem::mns
-{
-
-    ComponentPluginUser::ComponentPluginUser()
-    {
-        addPlugin(plugin);
-    }
-
-
-    armem::data::RegisterMemoryResult ComponentPluginUser::registerMemory(const armem::data::RegisterMemoryInput& input, const Ice::Current&)
-    {
-        std::scoped_lock lock(mnsMutex);
-        armem::data::RegisterMemoryResult result = mns.registerMemory(input);
-        return result;
-    }
-
-
-    armem::data::RemoveMemoryResult ComponentPluginUser::removeMemory(const armem::data::RemoveMemoryInput& input, const Ice::Current&)
-    {
-        std::scoped_lock lock(mnsMutex);
-        armem::data::RemoveMemoryResult result = mns.removeMemory(input);
-        return result;
-    }
-
-
-    armem::data::GetAllRegisteredMemoriesResult
-    ComponentPluginUser::getAllRegisteredMemories(const Ice::Current&)
-    {
-        std::scoped_lock lock(mnsMutex);
-        armem::data::GetAllRegisteredMemoriesResult result = mns.getAllRegisteredMemories();
-        return result;
-    }
-
-
-    armem::data::ResolveMemoryNameResult ComponentPluginUser::resolveMemoryName(const armem::data::ResolveMemoryNameInput& input, const Ice::Current&)
-    {
-        std::scoped_lock lock(mnsMutex);
-        armem::data::ResolveMemoryNameResult result = mns.resolveMemoryName(input);
-        return result;
-    }
-
-
-    armem::data::WaitForMemoryResult ComponentPluginUser::waitForMemory(const armem::data::WaitForMemoryInput& input, const Ice::Current&)
-    {
-        // No lock - this call blocks internally.
-        return mns.waitForMemory(input);
-    }
-
-}
diff --git a/source/RobotAPI/libraries/armem/mns/ComponentPlugin.h b/source/RobotAPI/libraries/armem/mns/ComponentPlugin.h
deleted file mode 100644
index 1347c197e6d4f560b5773abfed30b92e8f8a7604..0000000000000000000000000000000000000000
--- a/source/RobotAPI/libraries/armem/mns/ComponentPlugin.h
+++ /dev/null
@@ -1,62 +0,0 @@
-#pragma once
-
-#include <mutex>
-
-#include <ArmarXCore/core/Component.h>
-
-#include <RobotAPI/interface/armem/server/MemoryInterface.h>
-#include <RobotAPI/interface/armem/mns/MemoryNameSystemInterface.h>
-
-#include "MemoryNameSystem.h"
-
-
-namespace armarx::armem::mns::plugins
-{
-
-    class ComponentPlugin : public armarx::ComponentPlugin
-    {
-    public:
-        using armarx::ComponentPlugin::ComponentPlugin;
-    };
-
-}
-
-
-namespace armarx::armem::mns
-{
-
-    /**
-     * @brief Utility for connecting a Memory to Ice.
-     */
-    class ComponentPluginUser :
-        virtual public ManagedIceObject
-        , virtual public mns::MemoryNameSystemInterface
-    {
-    public:
-
-        ComponentPluginUser();
-
-        // mns::MemoryNameSystemInterface interface
-    public:
-        armem::data::RegisterMemoryResult registerMemory(const armem::data::RegisterMemoryInput& input, const Ice::Current& = Ice::emptyCurrent) override;
-        armem::data::RemoveMemoryResult removeMemory(const armem::data::RemoveMemoryInput& input, const Ice::Current& = Ice::emptyCurrent) override;
-        armem::data::GetAllRegisteredMemoriesResult getAllRegisteredMemories(const Ice::Current&) override;
-        armem::data::ResolveMemoryNameResult resolveMemoryName(const armem::data::ResolveMemoryNameInput& input, const Ice::Current& = Ice::emptyCurrent) override;
-        armem::data::WaitForMemoryResult waitForMemory(const armem::data::WaitForMemoryInput& input, const Ice::Current& = Ice::emptyCurrent) override;
-
-
-    public:
-
-        std::mutex mnsMutex;
-        MemoryNameSystem mns;
-
-
-    private:
-
-        plugins::ComponentPlugin* plugin = nullptr;
-
-
-    };
-
-
-}
diff --git a/source/RobotAPI/libraries/armem/mns/MemoryNameSystem.cpp b/source/RobotAPI/libraries/armem/mns/MemoryNameSystem.cpp
index 6e001784b90104580a49b2510bdb6583fa36783c..a80a189ff585c7610bebe0978468aec82ebe48b9 100644
--- a/source/RobotAPI/libraries/armem/mns/MemoryNameSystem.cpp
+++ b/source/RobotAPI/libraries/armem/mns/MemoryNameSystem.cpp
@@ -4,185 +4,41 @@
 namespace armarx::armem::mns
 {
 
-    MemoryNameSystem::MemoryNameSystem(const std::string& logTag)
+    // dto::WaitForServerResult MemoryNameSystem::waitForServer(const dto::WaitForServerInput& input)
+    void MemoryNameSystem::waitForServer_async(
+        const AMD_MemoryNameSystemInterface_waitForServerPtr& future,
+        const dto::WaitForServerInput& input)
     {
-        armarx::Logging::setTag(logTag);
+        waitForServerFutures[input.name].push_back(future);
+        waitForServer_processOnce();
     }
 
 
-    armem::data::RegisterMemoryResult MemoryNameSystem::registerMemory(const armem::data::RegisterMemoryInput& input)
+    void MemoryNameSystem::waitForServer_processOnce()
     {
-        armem::data::RegisterMemoryResult result;
-
-        if (!input.proxy)
-        {
-            result.success = false;
-            std::stringstream ss;
-            ss << "Could not register the memory '" << input.name << "'."
-               << "\nGiven proxy is null."
-               << "\nIf you want to remove a memory, use `removeMemory()`.";
-            result.errorMessage = ss.str();
-            return result;
-        }
-
-        auto it = memoryMap.find(input.name);
-        if (it == memoryMap.end())
-        {
-            it = memoryMap.emplace(input.name, MemoryInfo{}).first;
-        }
-        else if (!input.existOk)
-        {
-            result.success = false;
-            std::stringstream ss;
-            ss << "Could not register the memory '" << input.name << "'."
-               << "\nMemory '" << input.name << "' is already registered. "
-               << "\nIf this is ok, set 'existOk' to true when registering the memory.";
-            result.errorMessage = ss.str();
-            return result;
-        }
-
-        MemoryInfo& info = it->second;
-        info.name = input.name;
-        info.proxy = input.proxy;
-        info.timeRegistered = armem::Time::now();
-        ARMARX_DEBUG << "Registered memory '" << info.name << "'.";
-
-        {
-            std::unique_lock lock(waitForMemoryMutex);
-            waitForMemoryCond.notify_all();
-        }
-
-        result.success = true;
-        return result;
-    }
-
-
-    armem::data::RemoveMemoryResult MemoryNameSystem::removeMemory(const armem::data::RemoveMemoryInput& input)
-    {
-        armem::data::RemoveMemoryResult result;
-
-        if (auto it = memoryMap.find(input.name); it != memoryMap.end())
-        {
-            result.success = true;
-            memoryMap.erase(it);
-
-            ARMARX_DEBUG << "Removed memory '" << input.name << "'.";
-        }
-        else if (!input.notExistOk)
-        {
-            result.success = false;
-            std::stringstream ss;
-            ss << "Could not remove the memory '" << input.name << "."
-               << "\nMemory '" << input.name << "' is not registered. "
-               << "\nIf this is ok, set 'notExistOk' to true when removing the memory.";
-            result.errorMessage = ss.str();
-        }
-
-        return result;
-    }
-
-
-    data::GetAllRegisteredMemoriesResult
-    MemoryNameSystem::getAllRegisteredMemories()
-    {
-        data::GetAllRegisteredMemoriesResult result;
-        result.success = true;
-        result.errorMessage = "";
-
-        for (const auto& [name, info] : memoryMap)
+        for (auto it = waitForServerFutures.begin(); it != waitForServerFutures.end();)
         {
-            try
+            auto& [name, futures] = *it;
+            if (auto st = servers.find(name); st != servers.end())
             {
-                info.proxy->ice_ping();
-                result.proxies[name] = info.proxy;
-            }
-            catch (const Ice::Exception&)
-            {
-            }
-        }
-
-        return result;
-    }
-
-
-    armem::data::ResolveMemoryNameResult MemoryNameSystem::resolveMemoryName(const armem::data::ResolveMemoryNameInput& input)
-    {
-        armem::data::ResolveMemoryNameResult result;
-        try
-        {
-            MemoryInfo& info = memoryMap.at(input.name);
-
-            result.success = true;
-            result.proxy = info.proxy;
-
-            ARMARX_DEBUG << "Resolved memory name '" << input.name << "'.";
-        }
-        catch (const std::out_of_range&)
-        {
-            result.success = false;
-            std::stringstream ss;
-            ss << "Could not resolve the memory name '" << input.name << "'."
-               << "\nMemory '" << input.name << "' is not registered.";
-            result.errorMessage = ss.str();
-        }
-
-        return result;
-    }
-
-
-    data::WaitForMemoryResult MemoryNameSystem::waitForMemory(const data::WaitForMemoryInput& input)
-    {
-        data::ResolveMemoryNameInput resInput;
-        resInput.name = input.name;
-
-        Time start = Time::now();
-        data::ResolveMemoryNameResult resResult;
-        {
-            std::unique_lock lock(waitForMemoryMutex);
-            auto pred = [this, resInput, &resResult]()
-            {
-                resResult = resolveMemoryName(resInput);
-                return resResult.success;
-            };
-            if (input.timeoutMilliSeconds >= 0)
-            {
-                waitForMemoryCond.wait_for(lock, std::chrono::milliseconds(input.timeoutMilliSeconds), pred);
+                ServerInfo& info = st->second;
+
+                dto::WaitForServerResult result;
+                result.success = true;
+                result.server = info.server;
+
+                // Send responses and remove entry.
+                for (auto& future : futures)
+                {
+                    future->ice_response(result);
+                }
+                it = waitForServerFutures.erase(it);
             }
             else
             {
-                waitForMemoryCond.wait(lock, pred);
+                ++it;  // Skip.
             }
         }
-
-        armem::data::WaitForMemoryResult result;
-        result.success = resResult.success;
-
-        if (resResult.success)
-        {
-            ARMARX_CHECK(resResult.proxy);
-            result.proxy = resResult.proxy;
-        }
-        else
-        {
-            ARMARX_CHECK((Time::now() - start).toMilliSeconds() > input.timeoutMilliSeconds)
-                    << (Time::now() - start).toMilliSeconds() << " > " << input.timeoutMilliSeconds;
-
-            std::stringstream ss;
-            ss << "Timeout (" << input.timeoutMilliSeconds << " ms) while waiting for memory '" << input.name << "'.";
-            if (resResult.errorMessage.size() > 0)
-            {
-                ss << "\n" << resResult.errorMessage;
-            }
-            result.errorMessage = ss.str();
-        }
-
-        return result;
-    }
-
-
-    bool MemoryNameSystem::hasMemory(const std::string& memoryName) const
-    {
-        return memoryMap.count(memoryName) > 0;
     }
 
 
@@ -195,20 +51,41 @@ namespace armarx::armem::mns
         int row = 0;
         grid.add(Label("Memory Name"), {row, 0})
         .add(Label("Component Name"), {row, 1})
-        .add(Label("Registration Time"), {row, 2})
+        .add(Label("R/W"), {row, 2})
+        .add(Label("Registration Time"), {row, 3})
         ;
         row++;
 
-        for (const auto& [name, info] : memoryMap)
+        for (const auto& [name, info] : servers)
         {
             ARMARX_CHECK_EQUAL(name, info.name);
-            grid
-            .add(Label(name), {row, 0})
-            .add(Label(info.proxy->ice_getIdentity().name), {row, 1})
-            .add(Label(armem::toDateTimeMilliSeconds(info.timeRegistered, 0)), {row, 2})
-            ;
+            std::string componentName = "";
+            std::string mode = "";
+            if (info.server.reading)
+            {
+                componentName = info.server.reading->ice_getIdentity().name;
+                mode += "R";
+            }
+            if (info.server.writing)
+            {
+                componentName = info.server.writing->ice_getIdentity().name;
+                mode += "W";
+            }
+
+            int col = 0;
+            grid.add(Label(name), {row, col});
+            ++col;
+
+            grid.add(Label(componentName), {row, col});
+            ++col;
+
+            grid.add(Label(mode), {row, col});
+            ++col;
+
+            grid.add(Label(armem::toDateTimeMilliSeconds(info.timeRegistered, 0)), {row, col});
+            ++col;
 
-            row++;
+            ++row;
         }
 
         return grid;
diff --git a/source/RobotAPI/libraries/armem/mns/MemoryNameSystem.h b/source/RobotAPI/libraries/armem/mns/MemoryNameSystem.h
index 7372246d7e8059787f97f117931830d12c9dc082..51e4719f127ee576073e0c9b45cb0635241a185d 100644
--- a/source/RobotAPI/libraries/armem/mns/MemoryNameSystem.h
+++ b/source/RobotAPI/libraries/armem/mns/MemoryNameSystem.h
@@ -1,55 +1,36 @@
 #pragma once
 
-#include <condition_variable>
-#include <mutex>
-
-#include <ArmarXCore/core/logging/Logging.h>
+#include "Registry.h"
 
 #include <RobotAPI/interface/armem/mns/MemoryNameSystemInterface.h>
-#include <RobotAPI/interface/armem/server/MemoryInterface.h>
 
 #include <ArmarXGui/libraries/ArmarXGuiComponentPlugins/LightweightRemoteGuiComponentPlugin.h>
 
-#include "../core/Time.h"
+#include <map>
+#include <string>
 
 
 namespace armarx::armem::mns
 {
 
-    class MemoryNameSystem : armarx::Logging
+    class MemoryNameSystem : public Registry
     {
     public:
 
-        MemoryNameSystem(const std::string& logTag = "MemoryNameSystem");
-
-
-        /**
-         * @brief Register a new memory or update an existing entry.
-         *
-         * Causes threads waiting in `waitForMemory()` to resume if the respective
-         * memory was added.
-         */
-        data::RegisterMemoryResult registerMemory(const data::RegisterMemoryInput& input);
-        /**
-         * @brief Remove a memory entry.
-         */
-        data::RemoveMemoryResult removeMemory(const data::RemoveMemoryInput& input);
+        using WaitForServerFuturePtr = AMD_MemoryNameSystemInterface_waitForServerPtr;
 
-        data::GetAllRegisteredMemoriesResult getAllRegisteredMemories();
 
-        /**
-         * @brief Gets a memory entry, if it is available.
-         */
-        data::ResolveMemoryNameResult resolveMemoryName(const data::ResolveMemoryNameInput& input);
+    public:
 
         /**
-         * @brief Blocks until the specified memory is available, returning its proxy.
+         * @brief Store the call in a container for later response.
          */
-        data::WaitForMemoryResult waitForMemory(const data::WaitForMemoryInput& input);
+        void waitForServer_async(
+            const AMD_MemoryNameSystemInterface_waitForServerPtr& future,
+            const dto::WaitForServerInput& input);
 
+        void waitForServer_processOnce();
 
-        /// Indicates whether a memory entry for that name exists.
-        bool hasMemory(const std::string& memoryName) const;
 
         /// Builds a RemoteGui grid containing information about registered memories.
         armarx::RemoteGui::Client::GridLayout RemoteGui_buildInfoGrid();
@@ -57,22 +38,8 @@ namespace armarx::armem::mns
 
     public:
 
-        /// Information about a memory entry.
-        struct MemoryInfo
-        {
-            std::string name;
-            server::MemoryInterfacePrx proxy;
-            Time timeRegistered;
-        };
-
-        /// The registered memories.
-        std::map<std::string, MemoryInfo> memoryMap;
-
-
-        /// Mutex for `waitForMemoryCond`.
-        std::mutex waitForMemoryMutex;
-        /// Condition variable used by `waitForMemory()`.
-        std::condition_variable waitForMemoryCond;
+        /// Queued calls to `waitForServer`.
+        std::map<std::string, std::vector<WaitForServerFuturePtr>> waitForServerFutures;
 
     };
 
diff --git a/source/RobotAPI/libraries/armem/mns/Registry.cpp b/source/RobotAPI/libraries/armem/mns/Registry.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..260cfcd818a426ae7b4f18c6cde5a4180a459f0b
--- /dev/null
+++ b/source/RobotAPI/libraries/armem/mns/Registry.cpp
@@ -0,0 +1,162 @@
+#include "Registry.h"
+
+#include <ArmarXCore/core/logging/Logging.h>
+
+
+namespace armarx::armem::mns
+{
+
+    Registry::Registry(const std::string& logTag)
+    {
+        armarx::Logging::setTag(logTag);
+    }
+
+
+    bool Registry::hasServer(const std::string& memoryName) const
+    {
+        return servers.count(memoryName) > 0;
+    }
+
+
+    dto::RegisterServerResult Registry::registerServer(const dto::RegisterServerInput& input)
+    {
+        dto::RegisterServerResult result;
+
+        if (not(input.server.reading or input.server.writing))
+        {
+            result.success = false;
+            std::stringstream ss;
+            ss << "Could not register the memory server '" << input.name << "'."
+               << "\nGiven proxies are null."
+               << "\nIf you want to remove a memory server, use `removeServer()`.";
+            result.errorMessage = ss.str();
+            return result;
+        }
+
+        auto it = servers.find(input.name);
+        if (it == servers.end())
+        {
+            it = servers.emplace(input.name, ServerInfo{}).first;
+        }
+        else if (not input.existOk)
+        {
+            result.success = false;
+            std::stringstream ss;
+            ss << "Could not register the memory '" << input.name << "'."
+               << "\nMemory '" << input.name << "' is already registered. "
+               << "\nIf this is ok, set 'existOk' to true when registering the memory.";
+            result.errorMessage = ss.str();
+            return result;
+        }
+
+        ServerInfo& info = it->second;
+        info.name = input.name;
+        info.server = input.server;
+        info.timeRegistered = armem::Time::now();
+        ARMARX_DEBUG << "Registered memory '" << info.name << "'.";
+
+        result.success = true;
+        return result;
+    }
+
+
+    dto::RemoveServerResult Registry::removeServer(const dto::RemoveServerInput& input)
+    {
+        dto::RemoveServerResult result;
+
+        if (auto it = servers.find(input.name); it != servers.end())
+        {
+            result.success = true;
+            servers.erase(it);
+
+            ARMARX_DEBUG << "Removed memory '" << input.name << "'.";
+        }
+        else if (!input.notExistOk)
+        {
+            result.success = false;
+            std::stringstream ss;
+            ss << "Could not remove the memory '" << input.name << "."
+               << "\nMemory '" << input.name << "' is not registered. "
+               << "\nIf this is ok, set 'notExistOk' to true when removing the memory.";
+            result.errorMessage = ss.str();
+        }
+
+        return result;
+    }
+
+
+    template <class Prx>
+    bool isAvailable(const Prx& proxy)
+    {
+        if (proxy)
+        {
+            try
+            {
+                proxy->ice_ping();
+                return true;
+            }
+            catch (const Ice::Exception&)
+            {
+            }
+        }
+        return false;
+    }
+
+
+    dto::GetAllRegisteredServersResult
+    Registry::getAllRegisteredServers()
+    {
+        dto::GetAllRegisteredServersResult result;
+        result.success = true;
+        result.errorMessage = "";
+
+        for (const auto& [name, info] : servers)
+        {
+            if (isAvailable(info.server.reading) or isAvailable(info.server.writing))
+            {
+                result.servers[name] = info.server;
+            }
+        }
+
+        return result;
+    }
+
+
+    dto::ResolveServerResult Registry::resolveServer(const dto::ResolveServerInput& input)
+    {
+        dto::ResolveServerResult result;
+        try
+        {
+            ServerInfo& info = servers.at(input.name);
+
+            result.success = true;
+            result.server = info.server;
+
+            ARMARX_DEBUG << "Resolved memory name '" << input.name << "'.";
+        }
+        catch (const std::out_of_range&)
+        {
+            result.success = false;
+            std::stringstream ss;
+            ss << "Could not resolve the memory name '" << input.name << "'."
+               << "\nServer '" << input.name << "' is not registered.";
+            result.errorMessage = ss.str();
+        }
+
+        return result;
+    }
+
+
+    server::ReadingMemoryInterfacePrx getReadingInterface(const dto::MemoryServerInterfaces& server)
+    {
+        return server.reading;
+    }
+
+
+    server::WritingMemoryInterfacePrx getWritingInterface(const dto::MemoryServerInterfaces& server)
+    {
+        return server.writing;
+    }
+
+}
+
diff --git a/source/RobotAPI/libraries/armem/mns/Registry.h b/source/RobotAPI/libraries/armem/mns/Registry.h
new file mode 100644
index 0000000000000000000000000000000000000000..bf9348d157ee990f6032c4cf115b9fd56c70f716
--- /dev/null
+++ b/source/RobotAPI/libraries/armem/mns/Registry.h
@@ -0,0 +1,71 @@
+#pragma once
+
+#include <RobotAPI/libraries/armem/core/Time.h>
+
+#include <RobotAPI/interface/armem/mns/MemoryNameSystemInterface.h>
+#include <RobotAPI/interface/armem/server/ReadingMemoryInterface.h>
+#include <RobotAPI/interface/armem/server/WritingMemoryInterface.h>
+
+#include <ArmarXCore/core/logging/Logging.h>
+
+#include <map>
+#include <string>
+
+
+namespace armarx::armem::mns
+{
+
+    /**
+     * @brief A registry for memory servers.
+     */
+    class Registry : armarx::Logging
+    {
+    public:
+
+        Registry(const std::string& logTag = "MemoryNameSystem Registry");
+
+
+        /// Indicates whether a server entry for that name exists.
+        bool hasServer(const std::string& memoryName) const;
+
+
+        /**
+         * @brief Register a new memory server or update an existing entry.
+         *
+         * Causes threads waiting in `waitForMemory()` to resume if the respective
+         * memory server was added.
+         */
+        dto::RegisterServerResult registerServer(const dto::RegisterServerInput& input);
+        /**
+         * @brief Remove a server entry.
+         */
+        dto::RemoveServerResult removeServer(const dto::RemoveServerInput& input);
+
+
+        /**
+         * @brief Gets a server entry, if it is available.
+         */
+        dto::ResolveServerResult resolveServer(const dto::ResolveServerInput& input);
+
+        dto::GetAllRegisteredServersResult getAllRegisteredServers();
+
+
+    public:
+
+        /// Information about a memory entry.
+        struct ServerInfo
+        {
+            std::string name;
+            mns::dto::MemoryServerInterfaces server;
+            Time timeRegistered;
+        };
+
+        /// The registered memories.
+        std::map<std::string, ServerInfo> servers;
+
+    };
+
+
+    server::ReadingMemoryInterfacePrx getReadingInterface(const dto::MemoryServerInterfaces& server);
+    server::WritingMemoryInterfacePrx getWritingInterface(const dto::MemoryServerInterfaces& server);
+}
diff --git a/source/RobotAPI/libraries/armem/mns/plugins/Plugin.cpp b/source/RobotAPI/libraries/armem/mns/plugins/Plugin.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..a2e7c5dbf3fe87d6fdf24fee0181504a5f85abe9
--- /dev/null
+++ b/source/RobotAPI/libraries/armem/mns/plugins/Plugin.cpp
@@ -0,0 +1,8 @@
+#include "Plugin.h"
+
+
+namespace armarx::armem::mns::plugins
+{
+
+}
+
diff --git a/source/RobotAPI/libraries/armem/mns/plugins/Plugin.h b/source/RobotAPI/libraries/armem/mns/plugins/Plugin.h
new file mode 100644
index 0000000000000000000000000000000000000000..5caa973a9ebb7025f42978c608c033ce47722074
--- /dev/null
+++ b/source/RobotAPI/libraries/armem/mns/plugins/Plugin.h
@@ -0,0 +1,24 @@
+#pragma once
+
+#include <RobotAPI/libraries/armem/mns/MemoryNameSystem.h>
+
+#include <ArmarXCore/core/ComponentPlugin.h>
+
+
+namespace armarx::armem::mns::plugins
+{
+
+    class Plugin : public armarx::ComponentPlugin
+    {
+    public:
+
+        using armarx::ComponentPlugin::ComponentPlugin;
+
+
+    public:
+
+        MemoryNameSystem mns;
+
+    };
+
+}
diff --git a/source/RobotAPI/libraries/armem/mns/plugins/PluginUser.cpp b/source/RobotAPI/libraries/armem/mns/plugins/PluginUser.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..4ad29cdeec3c2b732cf1b9074931ab3c116fa42b
--- /dev/null
+++ b/source/RobotAPI/libraries/armem/mns/plugins/PluginUser.cpp
@@ -0,0 +1,69 @@
+#include "PluginUser.h"
+#include "Plugin.h"
+
+
+namespace armarx::armem::mns::plugins
+{
+
+    PluginUser::PluginUser()
+    {
+        addPlugin(plugin);
+    }
+
+
+    dto::RegisterServerResult PluginUser::registerServer(const dto::RegisterServerInput& input, const Ice::Current&)
+    {
+        std::scoped_lock lock(mnsMutex);
+        dto::RegisterServerResult result = plugin->mns.registerServer(input);
+        return result;
+    }
+
+
+    dto::RemoveServerResult PluginUser::removeServer(const dto::RemoveServerInput& input, const Ice::Current&)
+    {
+        std::scoped_lock lock(mnsMutex);
+        dto::RemoveServerResult result = plugin->mns.removeServer(input);
+        return result;
+    }
+
+
+    dto::GetAllRegisteredServersResult
+    PluginUser::getAllRegisteredServers(const Ice::Current&)
+    {
+        std::scoped_lock lock(mnsMutex);
+        dto::GetAllRegisteredServersResult result = plugin->mns.getAllRegisteredServers();
+        return result;
+    }
+
+
+    dto::ResolveServerResult PluginUser::resolveServer(const dto::ResolveServerInput& input, const Ice::Current&)
+    {
+        std::scoped_lock lock(mnsMutex);
+        dto::ResolveServerResult result = plugin->mns.resolveServer(input);
+        return result;
+    }
+
+
+    // dto::WaitForServerResult PluginUser::waitForServer(const dto::WaitForServerInput& input, const Ice::Current&)
+    void PluginUser::waitForServer_async(
+        const AMD_MemoryNameSystemInterface_waitForServerPtr& future,
+        const dto::WaitForServerInput& input,
+        const Ice::Current&)
+    {
+        std::scoped_lock lock(mnsMutex);
+        plugin->mns.waitForServer_async(future, input);
+    }
+
+
+    MemoryNameSystem& PluginUser::mns()
+    {
+        return plugin->mns;
+    }
+
+
+    const MemoryNameSystem& PluginUser::mns() const
+    {
+        return plugin->mns;
+    }
+
+}
diff --git a/source/RobotAPI/libraries/armem/mns/plugins/PluginUser.h b/source/RobotAPI/libraries/armem/mns/plugins/PluginUser.h
new file mode 100644
index 0000000000000000000000000000000000000000..1e8134ad5d372b1d69252cdc0cf2f5916c948b1e
--- /dev/null
+++ b/source/RobotAPI/libraries/armem/mns/plugins/PluginUser.h
@@ -0,0 +1,55 @@
+#pragma once
+
+#include <RobotAPI/libraries/armem/mns/MemoryNameSystem.h>
+
+#include <RobotAPI/interface/armem/mns/MemoryNameSystemInterface.h>
+
+#include <ArmarXCore/core/ManagedIceObject.h>
+
+#include <mutex>
+
+
+namespace armarx::armem::mns::plugins
+{
+    class Plugin;
+
+
+    class PluginUser :
+        virtual public ManagedIceObject
+        , virtual public mns::MemoryNameSystemInterface
+    {
+    public:
+
+        PluginUser();
+
+        // mns::MemoryNameSystemInterface interface
+    public:
+
+        dto::RegisterServerResult registerServer(const dto::RegisterServerInput& input, const Ice::Current& = Ice::emptyCurrent) override;
+        dto::RemoveServerResult removeServer(const dto::RemoveServerInput& input, const Ice::Current& = Ice::emptyCurrent) override;
+
+        dto::GetAllRegisteredServersResult getAllRegisteredServers(const Ice::Current&) override;
+
+        dto::ResolveServerResult resolveServer(const dto::ResolveServerInput& input, const Ice::Current& = Ice::emptyCurrent) override;
+
+        // Uses Asynchronous Method Dispatch (AMD)
+        void waitForServer_async(
+            const AMD_MemoryNameSystemInterface_waitForServerPtr& future,
+            const dto::WaitForServerInput& input,
+            const Ice::Current& = Ice::emptyCurrent) override;
+
+
+    protected:
+
+        std::mutex mnsMutex;
+        MemoryNameSystem& mns();
+        const MemoryNameSystem& mns() const;
+
+
+    private:
+
+        plugins::Plugin* plugin = nullptr;
+
+    };
+
+}
diff --git a/source/RobotAPI/libraries/armem/server/ComponentPlugin.cpp b/source/RobotAPI/libraries/armem/server/ComponentPlugin.cpp
index 93246434d7579368907c320b73379951765c548f..cc0d28920fd0500dfb36f0c8c30c83d1762810db 100644
--- a/source/RobotAPI/libraries/armem/server/ComponentPlugin.cpp
+++ b/source/RobotAPI/libraries/armem/server/ComponentPlugin.cpp
@@ -71,16 +71,17 @@ namespace armarx::armem::server::plugins
     }
 
 
-    data::RegisterMemoryResult ComponentPlugin::registerMemory(ComponentPluginUser& parent)
+    mns::dto::RegisterServerResult ComponentPlugin::registerMemory(ComponentPluginUser& parent)
     {
         MemoryID id = MemoryID().withMemoryName(parent.workingMemory().name());
-        MemoryInterfacePrx proxy = MemoryInterfacePrx::checkedCast(parent.getProxy());
-        ARMARX_CHECK_NOT_NULL(proxy);
+        mns::dto::MemoryServerInterfaces server;
+        server.reading = ReadingMemoryInterfacePrx::uncheckedCast(parent.getProxy());
+        server.writing = WritingMemoryInterfacePrx::uncheckedCast(parent.getProxy());
 
-        data::RegisterMemoryResult result;
+        mns::dto::RegisterServerResult result;
         try
         {
-            parent.memoryNameSystem().registerServer(id, proxy);
+            parent.memoryNameSystem().registerServer(id, server);
             result.success = true;
             ARMARX_DEBUG << "Registered memory server for " << id << " in the Memory Name System (MNS).";
         }
@@ -94,11 +95,11 @@ namespace armarx::armem::server::plugins
     }
 
 
-    data::RemoveMemoryResult ComponentPlugin::removeMemory(ComponentPluginUser& parent)
+    mns::dto::RemoveServerResult ComponentPlugin::removeMemory(ComponentPluginUser& parent)
     {
         MemoryID id = MemoryID().withMemoryName(parent.workingMemory().name());
 
-        data::RemoveMemoryResult result;
+        mns::dto::RemoveServerResult result;
         try
         {
             parent.memoryNameSystem().removeServer(id);
diff --git a/source/RobotAPI/libraries/armem/server/ComponentPlugin.h b/source/RobotAPI/libraries/armem/server/ComponentPlugin.h
index 4c9c66ee02ac3416da4b229df75d81522f6724a6..f198a23b1d4b969e41ddfaa3e2eb341b803bee40 100644
--- a/source/RobotAPI/libraries/armem/server/ComponentPlugin.h
+++ b/source/RobotAPI/libraries/armem/server/ComponentPlugin.h
@@ -47,14 +47,14 @@ namespace armarx::armem::server::plugins
          *
          * Called before onConnect() if MNS is enabled.
          */
-        data::RegisterMemoryResult registerMemory(ComponentPluginUser& parent);
+        mns::dto::RegisterServerResult registerMemory(ComponentPluginUser& parent);
 
         /**
          * @brief Remove the parent component from the MNS.
          *
          * Called before onDisconnect() if MNS is enabled.
          */
-        data::RemoveMemoryResult removeMemory(ComponentPluginUser& parent);
+        mns::dto::RemoveServerResult removeMemory(ComponentPluginUser& parent);