diff --git a/source/RobotAPI/libraries/armem/CMakeLists.txt b/source/RobotAPI/libraries/armem/CMakeLists.txt
index 88519c9ba53edf07b8c3ed5a1d7183cf8eb67d36..c524ecd93da7721ee95cc111beb518cafd848de5 100644
--- a/source/RobotAPI/libraries/armem/CMakeLists.txt
+++ b/source/RobotAPI/libraries/armem/CMakeLists.txt
@@ -80,7 +80,6 @@ set(LIB_FILES
 
 
     server/MemoryToIceAdapter.cpp
-    server/ComponentPlugin.cpp
     server/MemoryRemoteGui.cpp
     server/RemoteGuiAronDataVisitor.cpp
 
@@ -93,6 +92,10 @@ set(LIB_FILES
     server/wm/ice_conversions.cpp
     server/wm/detail/MaxHistorySize.cpp
 
+    server/plugins/Plugin.cpp
+    server/plugins/ReadOnlyPluginUser.cpp
+    server/plugins/ReadWritePluginUser.cpp
+
     server/segment/Segment.cpp
     server/segment/SpecializedSegment.cpp
 
@@ -188,7 +191,6 @@ set(LIB_HEADERS
     server.h
     server/forward_declarations.h
 
-    server/ComponentPlugin.h
     server/MemoryToIceAdapter.h
     server/MemoryRemoteGui.h
     server/RemoteGuiAronDataVisitor.h
@@ -202,6 +204,11 @@ set(LIB_HEADERS
     server/wm/ice_conversions.h
     server/wm/detail/MaxHistorySize.h
 
+    server/plugins.h
+    server/plugins/Plugin.h
+    server/plugins/ReadOnlyPluginUser.h
+    server/plugins/ReadWritePluginUser.h
+
     server/segment/Segment.h
     server/segment/SpecializedSegment.h
 
diff --git a/source/RobotAPI/libraries/armem/server/ComponentPlugin.cpp b/source/RobotAPI/libraries/armem/server/ComponentPlugin.cpp
deleted file mode 100644
index cc0d28920fd0500dfb36f0c8c30c83d1762810db..0000000000000000000000000000000000000000
--- a/source/RobotAPI/libraries/armem/server/ComponentPlugin.cpp
+++ /dev/null
@@ -1,211 +0,0 @@
-#include "ComponentPlugin.h"
-
-#include "MemoryToIceAdapter.h"
-
-#include <RobotAPI/libraries/armem/core/error.h>
-
-#include <ArmarXCore/core/Component.h>
-#include <ArmarXCore/core/exceptions/local/ExpressionException.h>
-
-
-namespace armarx::armem::server::plugins
-{
-    ComponentPlugin::~ComponentPlugin() = default;
-
-
-    ComponentPlugin::ComponentPlugin(ManagedIceObject& parent, std::string prefix) :
-        armarx::ComponentPlugin(parent, prefix)
-    {
-        addPlugin(clientPlugin);
-        ARMARX_CHECK_NOT_NULL(clientPlugin);
-        addPluginDependency(clientPlugin);
-    }
-
-
-    void ComponentPlugin::postCreatePropertyDefinitions(PropertyDefinitionsPtr& properties)
-    {
-        const std::string prefix = "mem.";
-        if (not workingMemory.name().empty()
-            and not properties->hasDefinition(prefix + "MemoryName"))
-        {
-            properties->optional(workingMemory.name(), prefix + "MemoryName", "Name of this memory server.");
-        }
-        properties->optional(longtermMemoryEnabled, prefix + "ltm.00_enabled");
-
-        properties->topic(memoryTopic, memoryTopicDefaultName);
-    }
-
-
-    void ComponentPlugin::postOnConnectComponent()
-    {
-        ComponentPluginUser& parent = this->parent<ComponentPluginUser>();
-
-        if (clientPlugin->isMemoryNameSystemEnabled() && parent.memoryNameSystem())
-        {
-            registerMemory(parent);
-        }
-        parent.iceAdapter().setMemoryListener(memoryTopic);
-
-        // establishing connection to ltm and mongodb
-        if (parent.isLongtermMemoryEnabled())
-        {
-            parent.longtermMemoryManager().reload();
-        }
-    }
-
-
-    void ComponentPlugin::preOnDisconnectComponent()
-    {
-        ComponentPluginUser& parent = this->parent<ComponentPluginUser>();
-        if (clientPlugin->isMemoryNameSystemEnabled() and clientPlugin->getMemoryNameSystemProxy())
-        {
-            removeMemory(parent);
-        }
-    }
-
-
-    void ComponentPlugin::setMemoryName(const std::string& memoryName)
-    {
-        workingMemory.name() = memoryName;
-        longtermMemoryManager.setName(memoryName);
-    }
-
-
-    mns::dto::RegisterServerResult ComponentPlugin::registerMemory(ComponentPluginUser& parent)
-    {
-        MemoryID id = MemoryID().withMemoryName(parent.workingMemory().name());
-        mns::dto::MemoryServerInterfaces server;
-        server.reading = ReadingMemoryInterfacePrx::uncheckedCast(parent.getProxy());
-        server.writing = WritingMemoryInterfacePrx::uncheckedCast(parent.getProxy());
-
-        mns::dto::RegisterServerResult result;
-        try
-        {
-            parent.memoryNameSystem().registerServer(id, server);
-            result.success = true;
-            ARMARX_DEBUG << "Registered memory server for " << id << " in the Memory Name System (MNS).";
-        }
-        catch (const armem::error::ServerRegistrationOrRemovalFailed& e)
-        {
-            result.success = false;
-            result.errorMessage = e.what();
-            ARMARX_WARNING << e.what();
-        }
-        return result;
-    }
-
-
-    mns::dto::RemoveServerResult ComponentPlugin::removeMemory(ComponentPluginUser& parent)
-    {
-        MemoryID id = MemoryID().withMemoryName(parent.workingMemory().name());
-
-        mns::dto::RemoveServerResult result;
-        try
-        {
-            parent.memoryNameSystem().removeServer(id);
-            result.success = true;
-            ARMARX_DEBUG << "Removed memory server for " << id << " from the Memory Name System (MNS).";
-        }
-        catch (const armem::error::ServerRegistrationOrRemovalFailed& e)
-        {
-            result.success = false;
-            result.errorMessage = e.what();
-            ARMARX_WARNING << e.what();
-        }
-        catch (const Ice::NotRegisteredException&)
-        {
-            // It's ok, the MNS is gone.
-            result.success = false;
-            result.errorMessage = "Memory Name System is gone.";
-        }
-        return result;
-    }
-
-}
-
-
-namespace armarx::armem::server
-{
-    ComponentPluginUser::ComponentPluginUser()
-    {
-        addPlugin(plugin);
-    }
-
-    ComponentPluginUser::~ComponentPluginUser() = default;
-
-    // Set the name of a memory
-    void ComponentPluginUser::setMemoryName(const std::string& memoryName)
-    {
-        plugin->setMemoryName(memoryName);
-    }
-
-
-    // WRITING
-    data::AddSegmentsResult ComponentPluginUser::addSegments(const data::AddSegmentsInput& input, const Ice::Current&)
-    {
-        ARMARX_TRACE;
-        bool addCoreSegmentOnUsage = false;
-        return addSegments(input, addCoreSegmentOnUsage);
-    }
-
-    data::AddSegmentsResult ComponentPluginUser::addSegments(const data::AddSegmentsInput& input, bool addCoreSegments)
-    {
-        ARMARX_TRACE;
-        data::AddSegmentsResult result = iceAdapter().addSegments(input, addCoreSegments);
-        return result;
-    }
-
-
-    data::CommitResult ComponentPluginUser::commit(const data::Commit& commitIce, const Ice::Current&)
-    {
-        ARMARX_TRACE;
-        return iceAdapter().commit(commitIce);
-    }
-
-
-    // READING
-    armem::query::data::Result ComponentPluginUser::query(const armem::query::data::Input& input, const Ice::Current&)
-    {
-        ARMARX_TRACE;
-        return iceAdapter().query(input);
-    }
-
-
-    // LTM STORING
-    data::StoreResult ComponentPluginUser::store(const data::StoreInput& input, const Ice::Current&)
-    {
-        ARMARX_TRACE;
-        return iceAdapter().store(input);
-    }
-
-
-    ComponentPlugin& ComponentPluginUser::memoryServerPlugin()
-    {
-        return *plugin;
-    }
-
-
-    wm::Memory& ComponentPluginUser::workingMemory()
-    {
-        return plugin->workingMemory;
-    }
-
-
-    MemoryToIceAdapter& ComponentPluginUser::iceAdapter()
-    {
-        return plugin->iceAdapter;
-    }
-
-
-    bool ComponentPluginUser::isLongtermMemoryEnabled()
-    {
-        return plugin->longtermMemoryEnabled;
-    }
-
-
-    ltm::mongodb::MemoryManager& ComponentPluginUser::longtermMemoryManager()
-    {
-        return plugin->longtermMemoryManager;
-    }
-
-}
diff --git a/source/RobotAPI/libraries/armem/server/ComponentPlugin.h b/source/RobotAPI/libraries/armem/server/ComponentPlugin.h
deleted file mode 100644
index f198a23b1d4b969e41ddfaa3e2eb341b803bee40..0000000000000000000000000000000000000000
--- a/source/RobotAPI/libraries/armem/server/ComponentPlugin.h
+++ /dev/null
@@ -1,155 +0,0 @@
-#pragma once
-
-#include "MemoryToIceAdapter.h"
-
-#include <RobotAPI/libraries/armem/core/wm/memory_definitions.h>
-#include <RobotAPI/libraries/armem/server/ltm/mongodb/MemoryManager.h>
-#include <RobotAPI/libraries/armem/client/plugins/Plugin.h>
-#include <RobotAPI/libraries/armem/client/plugins/ListeningPluginUser.h>
-
-#include <RobotAPI/interface/armem/server/MemoryInterface.h>
-#include <RobotAPI/interface/armem/client/MemoryListenerInterface.h>
-
-#include <ArmarXCore/core/ComponentPlugin.h>
-
-
-namespace armarx::armem::server
-{
-    class ComponentPluginUser;
-}
-namespace armarx::armem::server::plugins
-{
-
-    class ComponentPlugin :
-        public armarx::ComponentPlugin
-    {
-    public:
-
-        ComponentPlugin(ManagedIceObject& parent, std::string prefix);
-        virtual ~ComponentPlugin() override;
-
-        virtual void postCreatePropertyDefinitions(PropertyDefinitionsPtr& properties) override;
-
-        virtual void postOnConnectComponent() override;
-        virtual void preOnDisconnectComponent() override;
-
-
-    public:
-
-        /// Set the name of the wm and the ltm (if enabled).
-        void setMemoryName(const std::string& memoryName);
-
-
-    protected:
-
-        /**
-         * @brief Register the parent component in the MNS.
-         *
-         * Called before onConnect() if MNS is enabled.
-         */
-        mns::dto::RegisterServerResult registerMemory(ComponentPluginUser& parent);
-
-        /**
-         * @brief Remove the parent component from the MNS.
-         *
-         * Called before onDisconnect() if MNS is enabled.
-         */
-        mns::dto::RemoveServerResult removeMemory(ComponentPluginUser& parent);
-
-
-
-    public:
-
-        // Working Memory
-
-        /// The actual memory.
-        server::wm::Memory workingMemory;
-
-        /// Helps connecting `memory` to ice. Used to handle Ice callbacks.
-        MemoryToIceAdapter iceAdapter { &workingMemory, &longtermMemoryManager};
-
-
-        // Working Memory Updates
-
-        std::string memoryTopicDefaultName = "MemoryUpdates";
-        client::MemoryListenerInterfacePrx memoryTopic;
-
-
-        // Long-Term Memory
-
-        /// Indicates whether to use or not to use the ltm feature.
-        bool longtermMemoryEnabled = true;
-
-        /// A manager class for the ltm. It internally holds a normal wm instance as a cache.
-        server::ltm::mongodb::MemoryManager longtermMemoryManager;
-
-        std::string longTermMemoryDatabaseHost;
-        std::string longTermMemoryDatabaseUser;
-        std::string longTermMemoryDatabasePassword;
-
-
-    private:
-
-        client::plugins::Plugin* clientPlugin;
-
-    };
-
-}
-
-
-namespace armarx::armem::server
-{
-
-    /**
-     * @brief Base class of memory server components.
-     *
-     * Implements the server ice interfaces using the ice adapter of the plugin.
-     */
-    class ComponentPluginUser :
-        virtual public ManagedIceObject
-        , virtual public MemoryInterface
-        , virtual public client::plugins::ListeningPluginUser
-    {
-    public:
-
-        ComponentPluginUser();
-        virtual ~ComponentPluginUser() override;
-
-        /// Set the name of the wm and the ltm (if enabled)
-        void setMemoryName(const std::string& memoryName);
-
-
-        // WritingInterface interface
-        virtual data::AddSegmentsResult addSegments(const data::AddSegmentsInput& input, const Ice::Current& = Ice::emptyCurrent) override;
-        data::AddSegmentsResult addSegments(const data::AddSegmentsInput& input, bool addCoreSegments);
-
-        virtual data::CommitResult commit(const data::Commit& commit, const Ice::Current& = Ice::emptyCurrent) override;
-
-
-        // ReadingInterface interface
-        virtual armem::query::data::Result query(const armem::query::data::Input& input, const Ice::Current& = Ice::emptyCurrent) override;
-
-
-        // StoringInterface interface
-        virtual data::StoreResult store(const data::StoreInput&, const Ice::Current& = Ice::emptyCurrent) override;
-
-
-    public:
-
-        ComponentPlugin& memoryServerPlugin();
-
-        server::wm::Memory& workingMemory();
-        MemoryToIceAdapter& iceAdapter();
-
-        bool isLongtermMemoryEnabled();
-        server::ltm::mongodb::MemoryManager& longtermMemoryManager();
-
-
-    private:
-
-        plugins::ComponentPlugin* plugin = nullptr;
-
-    };
-
-
-}
diff --git a/source/RobotAPI/libraries/armem/server/forward_declarations.h b/source/RobotAPI/libraries/armem/server/forward_declarations.h
index 6872e2584352195ca8e587043e275acfbffb3739..d65ec0f36b9f60e680c6e720d80cd9cc3d6e789f 100644
--- a/source/RobotAPI/libraries/armem/server/forward_declarations.h
+++ b/source/RobotAPI/libraries/armem/server/forward_declarations.h
@@ -16,3 +16,7 @@ namespace armarx::armem::server::wm
     class CoreSegment;
     class Memory;
 }
+namespace armarx::armem::server::ltm::mongodb
+{
+    class MemoryManager;
+}
diff --git a/source/RobotAPI/libraries/armem/server/plugins.h b/source/RobotAPI/libraries/armem/server/plugins.h
new file mode 100644
index 0000000000000000000000000000000000000000..9f1255994daba045756a8c90dcbcfd57a9c63a11
--- /dev/null
+++ b/source/RobotAPI/libraries/armem/server/plugins.h
@@ -0,0 +1,20 @@
+#pragma once
+
+#include "plugins/Plugin.h"
+#include "plugins/ReadOnlyPluginUser.h"
+#include "plugins/ReadWritePluginUser.h"
+
+
+namespace armarx::armem::server
+{
+    using plugins::Plugin;
+    using plugins::ReadOnlyPluginUser;
+    using plugins::ReadWritePluginUser;
+}
+
+namespace armarx::armem
+{
+    using ServerPlugin = server::Plugin;
+    using ReadOnlyServerPluginUser = server::ReadOnlyPluginUser;
+    using ReadWriteServerPluginUser = server::ReadWritePluginUser;
+}
diff --git a/source/RobotAPI/libraries/armem/server/plugins/Plugin.cpp b/source/RobotAPI/libraries/armem/server/plugins/Plugin.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..031e8fbdfe55b1024bac050b341327e6ef16e482
--- /dev/null
+++ b/source/RobotAPI/libraries/armem/server/plugins/Plugin.cpp
@@ -0,0 +1,125 @@
+#include "Plugin.h"
+
+#include <RobotAPI/libraries/armem/core/error.h>
+#include <RobotAPI/libraries/armem/client/plugins/Plugin.h>
+
+#include <ArmarXCore/core/Component.h>
+#include <ArmarXCore/core/exceptions/local/ExpressionException.h>
+
+
+namespace armarx::armem::server::plugins
+{
+
+    Plugin::~Plugin() = default;
+
+
+    Plugin::Plugin(ManagedIceObject& parent, std::string prefix) :
+        armarx::ComponentPlugin(parent, prefix)
+    {
+        addPlugin(clientPlugin);
+        ARMARX_CHECK_NOT_NULL(clientPlugin);
+        addPluginDependency(clientPlugin);
+    }
+
+
+    void Plugin::postCreatePropertyDefinitions(PropertyDefinitionsPtr& properties)
+    {
+        const std::string prefix = "mem.";
+        if (not workingMemory.name().empty()
+            and not properties->hasDefinition(prefix + "MemoryName"))
+        {
+            properties->optional(workingMemory.name(), prefix + "MemoryName", "Name of this memory server.");
+        }
+        properties->optional(longtermMemoryEnabled, prefix + "ltm.00_enabled");
+
+
+        // Publish memory updates topic
+        properties->topic(memoryTopic, memoryTopicDefaultName);
+    }
+
+
+    void Plugin::postOnConnectComponent()
+    {
+        Component& parent = this->parent<Component>();
+
+        if (clientPlugin->isMemoryNameSystemEnabled() and clientPlugin->getMemoryNameSystemClient())
+        {
+            registerServer(parent);
+        }
+        iceAdapter.setMemoryListener(memoryTopic);
+
+        // establishing connection to ltm and mongodb
+        if (longtermMemoryEnabled)
+        {
+            longtermMemoryManager.reload();
+        }
+    }
+
+
+    void Plugin::preOnDisconnectComponent()
+    {
+        if (clientPlugin->isMemoryNameSystemEnabled() and clientPlugin->getMemoryNameSystemClient())
+        {
+            removeServer();
+        }
+    }
+
+
+    void Plugin::setMemoryName(const std::string& memoryName)
+    {
+        workingMemory.name() = memoryName;
+        longtermMemoryManager.setName(memoryName);
+    }
+
+
+    mns::dto::RegisterServerResult Plugin::registerServer(armarx::Component& parent)
+    {
+        MemoryID id = MemoryID().withMemoryName(workingMemory.name());
+        mns::dto::MemoryServerInterfaces server;
+        server.reading = ReadingMemoryInterfacePrx::uncheckedCast(parent.getProxy());
+        server.writing = WritingMemoryInterfacePrx::uncheckedCast(parent.getProxy());
+
+        mns::dto::RegisterServerResult result;
+        try
+        {
+            clientPlugin->getMemoryNameSystemClient().registerServer(id, server);
+            result.success = true;
+            ARMARX_DEBUG << "Registered memory server for " << id << " in the Memory Name System (MNS).";
+        }
+        catch (const armem::error::ServerRegistrationOrRemovalFailed& e)
+        {
+            result.success = false;
+            result.errorMessage = e.what();
+            ARMARX_WARNING << e.what();
+        }
+        return result;
+    }
+
+
+    mns::dto::RemoveServerResult Plugin::removeServer()
+    {
+        MemoryID id = MemoryID().withMemoryName(workingMemory.name());
+
+        mns::dto::RemoveServerResult result;
+        try
+        {
+            clientPlugin->getMemoryNameSystemClient().removeServer(id);
+            result.success = true;
+            ARMARX_DEBUG << "Removed memory server for " << id << " from the Memory Name System (MNS).";
+        }
+        catch (const armem::error::ServerRegistrationOrRemovalFailed& e)
+        {
+            result.success = false;
+            result.errorMessage = e.what();
+            ARMARX_WARNING << e.what();
+        }
+        catch (const Ice::NotRegisteredException&)
+        {
+            // It's ok, the MNS is gone.
+            result.success = false;
+            result.errorMessage = "Memory Name System is gone.";
+        }
+        return result;
+    }
+
+}
diff --git a/source/RobotAPI/libraries/armem/server/plugins/Plugin.h b/source/RobotAPI/libraries/armem/server/plugins/Plugin.h
new file mode 100644
index 0000000000000000000000000000000000000000..49cc07bb08dc7265fa797e2f5f77a3d81511c33c
--- /dev/null
+++ b/source/RobotAPI/libraries/armem/server/plugins/Plugin.h
@@ -0,0 +1,105 @@
+#pragma once
+
+#include <RobotAPI/libraries/armem/server/MemoryToIceAdapter.h>
+
+#include <RobotAPI/libraries/armem/server/wm/memory_definitions.h>
+#include <RobotAPI/libraries/armem/server/ltm/mongodb/MemoryManager.h>
+
+#include <RobotAPI/interface/armem/client/MemoryListenerInterface.h>
+#include <RobotAPI/interface/armem/mns/MemoryNameSystemInterface.h>
+
+#include <ArmarXCore/core/ComponentPlugin.h>
+
+
+namespace armarx
+{
+    class Component;
+}
+namespace armarx::armem::client::plugins
+{
+    class Plugin;
+}
+
+namespace armarx::armem::server::plugins
+{
+
+    class Plugin :
+        public armarx::ComponentPlugin
+    {
+    public:
+
+        Plugin(ManagedIceObject& parent, std::string prefix);
+        virtual ~Plugin() override;
+
+
+        virtual void postCreatePropertyDefinitions(PropertyDefinitionsPtr& properties) override;
+
+        virtual void postOnConnectComponent() override;
+        virtual void preOnDisconnectComponent() override;
+
+
+    public:
+
+        /// Set the name of the wm and the ltm (if enabled).
+        void setMemoryName(const std::string& memoryName);
+
+
+    protected:
+
+        /**
+         * @brief Register the parent component in the MNS.
+         *
+         * Called before onConnect() if MNS is enabled.
+         */
+        mns::dto::RegisterServerResult registerServer(armarx::Component& parent);
+
+        /**
+         * @brief Remove the parent component from the MNS.
+         *
+         * Called before onDisconnect() if MNS is enabled.
+         */
+        mns::dto::RemoveServerResult removeServer();
+
+
+
+    public:
+
+        // Working Memory
+
+        /// The actual memory.
+        server::wm::Memory workingMemory;
+
+        /// Helps connecting `memory` to ice. Used to handle Ice callbacks.
+        MemoryToIceAdapter iceAdapter { &workingMemory, &longtermMemoryManager};
+
+
+        // Working Memory Updates (publishing)
+
+        std::string memoryTopicDefaultName = "MemoryUpdates";
+        client::MemoryListenerInterfacePrx memoryTopic;
+
+
+        // Long-Term Memory
+
+        /// Indicates whether to use or not to use the ltm feature.
+        bool longtermMemoryEnabled = true;
+
+        /// A manager class for the ltm. It internally holds a normal wm instance as a cache.
+        server::ltm::mongodb::MemoryManager longtermMemoryManager;
+
+        std::string longTermMemoryDatabaseHost;
+        std::string longTermMemoryDatabaseUser;
+        std::string longTermMemoryDatabasePassword;
+
+
+    private:
+
+        client::plugins::Plugin* clientPlugin;
+
+    };
+}
+
+namespace armarx::armem::server
+{
+    using plugins::Plugin;
+}
diff --git a/source/RobotAPI/libraries/armem/server/plugins/ReadOnlyPluginUser.cpp b/source/RobotAPI/libraries/armem/server/plugins/ReadOnlyPluginUser.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b95b94afb85f31efd41384283409460b706a729e
--- /dev/null
+++ b/source/RobotAPI/libraries/armem/server/plugins/ReadOnlyPluginUser.cpp
@@ -0,0 +1,56 @@
+#include "ReadOnlyPluginUser.h"
+#include "Plugin.h"
+
+#include <RobotAPI/libraries/armem/core/error.h>
+#include <RobotAPI/libraries/armem/server/MemoryToIceAdapter.h>
+
+#include <ArmarXCore/core/Component.h>
+#include <ArmarXCore/core/exceptions/local/ExpressionException.h>
+
+
+
+namespace armarx::armem::server::plugins
+{
+
+    ReadOnlyPluginUser::ReadOnlyPluginUser()
+    {
+        addPlugin(plugin);
+    }
+
+
+    ReadOnlyPluginUser::~ReadOnlyPluginUser()
+    {
+    }
+
+
+    void ReadOnlyPluginUser::setMemoryName(const std::string& memoryName)
+    {
+        plugin->setMemoryName(memoryName);
+    }
+
+
+    armem::query::data::Result ReadOnlyPluginUser::query(const armem::query::data::Input& input, const Ice::Current&)
+    {
+        ARMARX_TRACE;
+        return iceAdapter().query(input);
+    }
+
+
+    Plugin& ReadOnlyPluginUser::memoryServerPlugin()
+    {
+        return *plugin;
+    }
+
+
+    wm::Memory& ReadOnlyPluginUser::workingMemory()
+    {
+        return plugin->workingMemory;
+    }
+
+
+    MemoryToIceAdapter& ReadOnlyPluginUser::iceAdapter()
+    {
+        return plugin->iceAdapter;
+    }
+
+}
diff --git a/source/RobotAPI/libraries/armem/server/plugins/ReadOnlyPluginUser.h b/source/RobotAPI/libraries/armem/server/plugins/ReadOnlyPluginUser.h
new file mode 100644
index 0000000000000000000000000000000000000000..f56d66b0f35e173d3076dedb729a7dc77ab9bb6b
--- /dev/null
+++ b/source/RobotAPI/libraries/armem/server/plugins/ReadOnlyPluginUser.h
@@ -0,0 +1,61 @@
+#pragma once
+
+#include <RobotAPI/libraries/armem/server/forward_declarations.h>
+
+#include <RobotAPI/libraries/armem/client/plugins/PluginUser.h>
+#include <RobotAPI/interface/armem/server/MemoryInterface.h>
+
+#include <ArmarXCore/core/ManagedIceObject.h>
+
+
+namespace armarx::armem::server::plugins
+{
+
+    class Plugin;
+
+
+    /**
+     * @brief Base class of memory server components.
+     *
+     * Implements the server ice interfaces using the ice adapter of the plugin.
+     */
+    class ReadOnlyPluginUser :
+        virtual public ManagedIceObject
+        , virtual public ReadingMemoryInterface
+        , virtual public client::plugins::PluginUser
+    {
+    public:
+
+        ReadOnlyPluginUser();
+        virtual ~ReadOnlyPluginUser() override;
+
+
+        void setMemoryName(const std::string& memoryName);
+
+
+        // ReadingInterface interface
+        virtual armem::query::data::Result query(
+                const armem::query::data::Input& input,
+                const Ice::Current& = Ice::emptyCurrent) override;
+
+
+    public:
+
+        Plugin& memoryServerPlugin();
+
+        server::wm::Memory& workingMemory();
+        MemoryToIceAdapter& iceAdapter();
+
+
+    private:
+
+        plugins::Plugin* plugin = nullptr;
+
+    };
+
+}
+
+namespace armarx::armem::server
+{
+    using plugins::ReadOnlyPluginUser;
+}
diff --git a/source/RobotAPI/libraries/armem/server/plugins/ReadWritePluginUser.cpp b/source/RobotAPI/libraries/armem/server/plugins/ReadWritePluginUser.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..f3da4f3ee885a2f1cda0a86ad195ae466f4fb9e5
--- /dev/null
+++ b/source/RobotAPI/libraries/armem/server/plugins/ReadWritePluginUser.cpp
@@ -0,0 +1,100 @@
+#include "ReadWritePluginUser.h"
+#include "Plugin.h"
+
+#include <RobotAPI/libraries/armem/core/error.h>
+#include <RobotAPI/libraries/armem/server/MemoryToIceAdapter.h>
+
+#include <ArmarXCore/core/Component.h>
+#include <ArmarXCore/core/exceptions/local/ExpressionException.h>
+
+
+
+namespace armarx::armem::server::plugins
+{
+
+    ReadWritePluginUser::ReadWritePluginUser()
+    {
+        addPlugin(plugin);
+    }
+
+
+    ReadWritePluginUser::~ReadWritePluginUser()
+    {
+    }
+
+
+    void ReadWritePluginUser::setMemoryName(const std::string& memoryName)
+    {
+        plugin->setMemoryName(memoryName);
+    }
+
+
+    // WRITING
+    data::AddSegmentsResult ReadWritePluginUser::addSegments(const data::AddSegmentsInput& input, const Ice::Current&)
+    {
+        ARMARX_TRACE;
+        bool addCoreSegmentOnUsage = false;
+        return addSegments(input, addCoreSegmentOnUsage);
+    }
+
+    data::AddSegmentsResult ReadWritePluginUser::addSegments(const data::AddSegmentsInput& input, bool addCoreSegments)
+    {
+        ARMARX_TRACE;
+        data::AddSegmentsResult result = iceAdapter().addSegments(input, addCoreSegments);
+        return result;
+    }
+
+
+    data::CommitResult ReadWritePluginUser::commit(const data::Commit& commitIce, const Ice::Current&)
+    {
+        ARMARX_TRACE;
+        return iceAdapter().commit(commitIce);
+    }
+
+
+    // READING
+    armem::query::data::Result ReadWritePluginUser::query(const armem::query::data::Input& input, const Ice::Current&)
+    {
+        ARMARX_TRACE;
+        return iceAdapter().query(input);
+    }
+
+
+    // LTM STORING
+    data::StoreResult ReadWritePluginUser::store(const data::StoreInput& input, const Ice::Current&)
+    {
+        ARMARX_TRACE;
+        return iceAdapter().store(input);
+    }
+
+
+    Plugin& ReadWritePluginUser::memoryServerPlugin()
+    {
+        return *plugin;
+    }
+
+
+    wm::Memory& ReadWritePluginUser::workingMemory()
+    {
+        return plugin->workingMemory;
+    }
+
+
+    MemoryToIceAdapter& ReadWritePluginUser::iceAdapter()
+    {
+        return plugin->iceAdapter;
+    }
+
+
+    bool ReadWritePluginUser::isLongtermMemoryEnabled()
+    {
+        return plugin->longtermMemoryEnabled;
+    }
+
+
+    ltm::mongodb::MemoryManager& ReadWritePluginUser::longtermMemoryManager()
+    {
+        return plugin->longtermMemoryManager;
+    }
+
+}
diff --git a/source/RobotAPI/libraries/armem/server/plugins/ReadWritePluginUser.h b/source/RobotAPI/libraries/armem/server/plugins/ReadWritePluginUser.h
new file mode 100644
index 0000000000000000000000000000000000000000..6736224199489fb171d49b092fd91e88e59fd9b0
--- /dev/null
+++ b/source/RobotAPI/libraries/armem/server/plugins/ReadWritePluginUser.h
@@ -0,0 +1,74 @@
+#pragma once
+
+#include <RobotAPI/libraries/armem/server/forward_declarations.h>
+
+#include <RobotAPI/libraries/armem/client/plugins/ListeningPluginUser.h>
+#include <RobotAPI/interface/armem/server/MemoryInterface.h>
+
+#include <ArmarXCore/core/ManagedIceObject.h>
+
+
+namespace armarx::armem::server::plugins
+{
+
+    class Plugin;
+
+
+    /**
+     * @brief Base class of memory server components.
+     *
+     * Implements the server ice interfaces using the ice adapter of the plugin.
+     */
+    class ReadWritePluginUser :
+        virtual public ManagedIceObject
+        , virtual public MemoryInterface
+        , virtual public client::plugins::ListeningPluginUser
+    {
+    public:
+
+        ReadWritePluginUser();
+        virtual ~ReadWritePluginUser() override;
+
+
+        void setMemoryName(const std::string& memoryName);
+
+
+        // WritingInterface interface
+        virtual data::AddSegmentsResult addSegments(const data::AddSegmentsInput& input, const Ice::Current& = Ice::emptyCurrent) override;
+        data::AddSegmentsResult addSegments(const data::AddSegmentsInput& input, bool addCoreSegments);
+
+        virtual data::CommitResult commit(const data::Commit& commit, const Ice::Current& = Ice::emptyCurrent) override;
+
+
+        // ReadingInterface interface
+        virtual armem::query::data::Result query(const armem::query::data::Input& input, const Ice::Current& = Ice::emptyCurrent) override;
+
+
+        // StoringInterface interface
+        virtual data::StoreResult store(const data::StoreInput&, const Ice::Current& = Ice::emptyCurrent) override;
+
+
+    public:
+
+        Plugin& memoryServerPlugin();
+
+        server::wm::Memory& workingMemory();
+        MemoryToIceAdapter& iceAdapter();
+
+        bool isLongtermMemoryEnabled();
+        server::ltm::mongodb::MemoryManager& longtermMemoryManager();
+
+
+    private:
+
+        plugins::Plugin* plugin = nullptr;
+
+    };
+
+}
+
+namespace armarx::armem::server
+{
+    using plugins::ReadWritePluginUser;
+}
+