diff --git a/cmdline/CtaAdminCmd.cpp b/cmdline/CtaAdminCmd.cpp
index 7d9d5bf7cf7d7564ba809803ebe741eabda5434f..a65c5bfa02c10c206ee9aaad4191c936684bdedc 100644
--- a/cmdline/CtaAdminCmd.cpp
+++ b/cmdline/CtaAdminCmd.cpp
@@ -83,8 +83,12 @@ void IStreamBuffer<cta::xrd::Data>::DataCallback(cta::xrd::Data record) const
          case Data::kLpaSummary:    std::cout << Log::DumpProtobuf(&record.lpa_summary());  break;
          case Data::kLprItem:       std::cout << Log::DumpProtobuf(&record.lpr_item());     break;
          case Data::kLprSummary:    std::cout << Log::DumpProtobuf(&record.lpr_summary());  break;
+         case Data::kLllsItem:      std::cout << Log::DumpProtobuf(&record.llls_item());    break;
+         case Data::kMplsItem:      std::cout << Log::DumpProtobuf(&record.mpls_item());    break;
          case Data::kRelsItem:      std::cout << Log::DumpProtobuf(&record.rels_item());    break;
          case Data::kRmrlsItem:     std::cout << Log::DumpProtobuf(&record.rmrls_item());   break;
+         case Data::kSqItem:        std::cout << Log::DumpProtobuf(&record.sq_item());      break;
+         case Data::kSclsItem:      std::cout << Log::DumpProtobuf(&record.scls_item());    break;
          case Data::kTalsItem:      std::cout << Log::DumpProtobuf(&record.tals_item());    break;
          case Data::kTplsItem:      std::cout << Log::DumpProtobuf(&record.tpls_item());    break;
          default:
@@ -105,8 +109,12 @@ void IStreamBuffer<cta::xrd::Data>::DataCallback(cta::xrd::Data record) const
          case Data::kLpaSummary:    formattedText.print(record.lpa_summary());  break;
          case Data::kLprItem:       formattedText.print(record.lpr_item());     break;
          case Data::kLprSummary:    formattedText.print(record.lpr_summary());  break;
+         case Data::kLllsItem:      formattedText.print(record.llls_item());    break;
+         case Data::kMplsItem:      formattedText.print(record.mpls_item());    break;
          case Data::kRelsItem:      formattedText.print(record.rels_item());    break;
          case Data::kRmrlsItem:     formattedText.print(record.rmrls_item());   break;
+         case Data::kSqItem:        formattedText.print(record.sq_item());      break;
+         case Data::kSclsItem:      formattedText.print(record.scls_item());    break;
          case Data::kTalsItem:      formattedText.print(record.tals_item());    break;
          case Data::kTplsItem:      formattedText.print(record.tpls_item());    break;
          default:
@@ -254,8 +262,12 @@ void CtaAdminCmd::send() const
             case HeaderType::LISTPENDINGARCHIVES_SUMMARY:  formattedText.printListPendingArchivesSummaryHeader(); break;
             case HeaderType::LISTPENDINGRETRIEVES:         formattedText.printListPendingRetrievesHeader(); break;
             case HeaderType::LISTPENDINGRETRIEVES_SUMMARY: formattedText.printListPendingRetrievesSummaryHeader(); break;
+            case HeaderType::LOGICALLIBRARY_LS:            formattedText.printLogicalLibraryLsHeader(); break;
+            case HeaderType::MOUNTPOLICY_LS:               formattedText.printMountPolicyLsHeader(); break;
             case HeaderType::REPACK_LS:                    formattedText.printRepackLsHeader(); break;
             case HeaderType::REQUESTERMOUNTRULE_LS:        formattedText.printRequesterMountRuleLsHeader(); break;
+            case HeaderType::SHOWQUEUES:                   formattedText.printShowQueuesHeader(); break;
+            case HeaderType::STORAGECLASS_LS:              formattedText.printStorageClassLsHeader(); break;
             case HeaderType::TAPE_LS:                      formattedText.printTapeLsHeader(); break;
             case HeaderType::TAPEPOOL_LS:                  formattedText.printTapePoolLsHeader(); break;
             case HeaderType::NONE:
diff --git a/cmdline/CtaAdminTextFormatter.cpp b/cmdline/CtaAdminTextFormatter.cpp
index 56f7765c0ecbc05b1ac86e65cee811e7373cf7a2..ff48242ad6a01e6c74dcc05ab1cbb6c22ce8f5c9 100644
--- a/cmdline/CtaAdminTextFormatter.cpp
+++ b/cmdline/CtaAdminTextFormatter.cpp
@@ -500,6 +500,72 @@ void TextFormatter::print(const ListPendingRetrievesSummary &lpr_summary) {
   );
 }
 
+void TextFormatter::printLogicalLibraryLsHeader() {
+  push_back("HEADER");
+  push_back(
+    "name",
+    "disabled",
+    "c.user",
+    "c.host",
+    "c.time",
+    "m.user",
+    "m.host",
+    "m.time",
+    "comment"
+  );
+}
+
+void TextFormatter::print(const LogicalLibraryLsItem &llls_item) {
+  push_back(
+    llls_item.name(),
+    llls_item.is_disabled(),
+    llls_item.creation_log().username(),
+    llls_item.creation_log().host(),
+    llls_item.creation_log().time(),
+    llls_item.last_modification_log().username(),
+    llls_item.last_modification_log().host(),
+    llls_item.last_modification_log().time(),
+    llls_item.comment()
+  );
+}
+
+void TextFormatter::printMountPolicyLsHeader() {
+  push_back("HEADER");
+  push_back(
+    "mount policy",
+    "a.priority",
+    "a.minAge",
+    "r.priority",
+    "r.minAge",
+    "max drives",
+    "c.user",
+    "c.host",
+    "c.time",
+    "m.user",
+    "m.host",
+    "m.time",
+    "comment"
+  );
+}
+
+void TextFormatter::print(const MountPolicyLsItem &mpls_item) {
+  push_back(
+    mpls_item.name(),
+    mpls_item.archive_priority(),
+    mpls_item.archive_min_request_age(),
+    mpls_item.retrieve_priority(),
+    mpls_item.retrieve_min_request_age(),
+    mpls_item.max_drives_allowed(),
+    mpls_item.creation_log().username(),
+    mpls_item.creation_log().host(),
+    mpls_item.creation_log().time(),
+    mpls_item.last_modification_log().username(),
+    mpls_item.last_modification_log().host(),
+    mpls_item.last_modification_log().time(),
+    mpls_item.comment()
+  );
+}
+
 void TextFormatter::printRepackLsHeader() {
   push_back("HEADER");
   push_back(
@@ -572,6 +638,103 @@ void TextFormatter::print(const RequesterMountRuleLsItem &rmrls_item) {
   );
 }
 
+void TextFormatter::printShowQueuesHeader() {
+  push_back("HEADER");
+  push_back(
+    "type",
+    "tapepool",
+    "logical library",
+    "vid",
+    "files queued",
+    "data queued",
+    "oldest age",
+    "priority",
+    "min age",
+    "max drives",
+    "cur. mounts",
+    "cur. files",
+    "cur. data",
+    "MB/s",
+    "next mounts",
+    "tapes capacity",
+    "files on tapes",
+    "data on tapes",
+    "full tapes",
+    "empty tapes",
+    "disabled tapes",
+    "writable tapes"
+  );
+}
+
+void TextFormatter::print(const ShowQueuesItem &sq_item) {
+  std::string priority;
+  std::string minAge;
+  std::string maxDrivesAllowed;
+
+  if(sq_item.mount_type() == ARCHIVE_FOR_USER ||
+     sq_item.mount_type() == RETRIEVE) {
+    priority         = std::to_string(sq_item.priority());
+    minAge           = std::to_string(sq_item.min_age());
+    maxDrivesAllowed = std::to_string(sq_item.max_drives());
+  }
+
+  push_back(
+    toString(ProtobufToMountType(sq_item.mount_type())),
+    sq_item.tapepool(),
+    sq_item.logical_library(),
+    sq_item.vid(),
+    sq_item.queued_files(),
+    dataSizeToStr(sq_item.queued_bytes()),
+    sq_item.oldest_age(),
+    priority,
+    minAge,
+    maxDrivesAllowed,
+    sq_item.cur_mounts(),
+    sq_item.cur_files(),
+    dataSizeToStr(sq_item.cur_bytes()),
+    sq_item.bytes_per_second() / 1000000,
+    sq_item.next_mounts(),
+    dataSizeToStr(sq_item.tapes_capacity()),
+    sq_item.tapes_files(),
+    dataSizeToStr(sq_item.tapes_bytes()),
+    sq_item.full_tapes(),
+    sq_item.empty_tapes(),
+    sq_item.disabled_tapes(),
+    sq_item.writable_tapes()
+  );
+}
+
+void TextFormatter::printStorageClassLsHeader() {
+  push_back("HEADER");
+  push_back(
+    "instance",
+    "storage class",
+    "number of copies",
+    "c.user",
+    "c.host",
+    "c.time",
+    "m.user",
+    "m.host",
+    "m.time",
+    "comment"
+  );
+}
+
+void TextFormatter::print(const StorageClassLsItem &scls_item) {
+  push_back(
+    scls_item.disk_instance(),
+    scls_item.name(),
+    scls_item.nb_copies(),
+    scls_item.creation_log().username(),
+    scls_item.creation_log().host(),
+    scls_item.creation_log().time(),
+    scls_item.last_modification_log().username(),
+    scls_item.last_modification_log().host(),
+    scls_item.last_modification_log().time(),
+    scls_item.comment()
+  );
+}
+
 void TextFormatter::printTapeLsHeader() {
   push_back("HEADER");
   push_back(
diff --git a/cmdline/CtaAdminTextFormatter.hpp b/cmdline/CtaAdminTextFormatter.hpp
index b2a902dd9c6217a48d365f0c6d8bcf6b286ae1b4..533e534f5d414e4a322175f45890fbf57a20d1a0 100644
--- a/cmdline/CtaAdminTextFormatter.hpp
+++ b/cmdline/CtaAdminTextFormatter.hpp
@@ -56,8 +56,12 @@ public:
   void printListPendingArchivesSummaryHeader();
   void printListPendingRetrievesHeader();
   void printListPendingRetrievesSummaryHeader();
+  void printLogicalLibraryLsHeader();
+  void printMountPolicyLsHeader();
   void printRepackLsHeader();
   void printRequesterMountRuleLsHeader();
+  void printShowQueuesHeader();
+  void printStorageClassLsHeader();
   void printTapeLsHeader();
   void printTapePoolLsHeader();
    
@@ -74,8 +78,12 @@ public:
   void print(const ListPendingArchivesSummary &lpa_summary);
   void print(const ListPendingRetrievesItem &lpr_item);
   void print(const ListPendingRetrievesSummary &lpr_summary);
+  void print(const LogicalLibraryLsItem &llls_item);
+  void print(const MountPolicyLsItem &mpls_item);
   void print(const RepackLsItem &rels_item);
   void print(const RequesterMountRuleLsItem &rmrls_item);
+  void print(const ShowQueuesItem &sq_item);
+  void print(const StorageClassLsItem &scls_item);
   void print(const TapeLsItem &tals_item);
   void print(const TapePoolLsItem &tpls_item);
 
diff --git a/common/dataStructures/MountTypeSerDeser.hpp b/common/dataStructures/MountTypeSerDeser.hpp
index 3774d324d6f8e0925749e4a639f7ece6f6b480a2..0e6855cd8797b612784e9d0141616f5d9e2b251b 100644
--- a/common/dataStructures/MountTypeSerDeser.hpp
+++ b/common/dataStructures/MountTypeSerDeser.hpp
@@ -24,34 +24,34 @@
 namespace cta {
 namespace admin {
 
-common::dataStructures::MountType ProtobufToMountType(DriveLsItem::MountType mountType) {
+common::dataStructures::MountType ProtobufToMountType(MountType mountType) {
   using namespace common::dataStructures;
 
   switch(mountType) {
-    case DriveLsItem::NO_MOUNT:              return MountType::NoMount;
-    case DriveLsItem::ARCHIVE_FOR_USER:      return MountType::ArchiveForUser;
-    case DriveLsItem::ARCHIVE_FOR_REPACK:    return MountType::ArchiveForRepack;
-    case DriveLsItem::ARCHIVE_ALL_TYPES:     return MountType::ArchiveAllTypes;
-    case DriveLsItem::RETRIEVE:              return MountType::Retrieve;
-    case DriveLsItem::LABEL:                 return MountType::Label;
-    case DriveLsItem::UNKNOWN_MOUNT_TYPE:
+    case NO_MOUNT:              return common::dataStructures::MountType::NoMount;
+    case ARCHIVE_FOR_USER:      return common::dataStructures::MountType::ArchiveForUser;
+    case ARCHIVE_FOR_REPACK:    return common::dataStructures::MountType::ArchiveForRepack;
+    case ARCHIVE_ALL_TYPES:     return common::dataStructures::MountType::ArchiveAllTypes;
+    case RETRIEVE:              return common::dataStructures::MountType::Retrieve;
+    case LABEL:                 return common::dataStructures::MountType::Label;
+    case UNKNOWN_MOUNT_TYPE:
     default:
       throw std::runtime_error("In ProtobufToMountType(): unknown mount type " + std::to_string(mountType));
   }
 }
 
-DriveLsItem::MountType MountTypeToProtobuf(common::dataStructures::MountType mountType) {
+MountType MountTypeToProtobuf(common::dataStructures::MountType mountType) {
   using namespace common::dataStructures;
 
   switch(mountType) {
-    case MountType::NoMount:                 return DriveLsItem::NO_MOUNT;
-    case MountType::ArchiveForUser:          return DriveLsItem::ARCHIVE_FOR_USER;
-    case MountType::ArchiveForRepack:        return DriveLsItem::ARCHIVE_FOR_REPACK;
-    case MountType::ArchiveAllTypes:         return DriveLsItem::ARCHIVE_ALL_TYPES;
-    case MountType::Retrieve:                return DriveLsItem::RETRIEVE;
-    case MountType::Label:                   return DriveLsItem::LABEL;
+    case common::dataStructures::MountType::NoMount:             return NO_MOUNT;
+    case common::dataStructures::MountType::ArchiveForUser:      return ARCHIVE_FOR_USER;
+    case common::dataStructures::MountType::ArchiveForRepack:    return ARCHIVE_FOR_REPACK;
+    case common::dataStructures::MountType::ArchiveAllTypes:     return ARCHIVE_ALL_TYPES;
+    case common::dataStructures::MountType::Retrieve:            return RETRIEVE;
+    case common::dataStructures::MountType::Label:               return LABEL;
   }
-  return DriveLsItem::UNKNOWN_MOUNT_TYPE;
+  return UNKNOWN_MOUNT_TYPE;
 }
 
 }} // cta::admin
diff --git a/xroot_plugins/XrdCtaDriveLs.hpp b/xroot_plugins/XrdCtaDriveLs.hpp
index 7d1df9bf5a6442681fd586df9aed810f6575ff22..58aeb8000aa711978e99cd0eefdd512c9ea91e92 100644
--- a/xroot_plugins/XrdCtaDriveLs.hpp
+++ b/xroot_plugins/XrdCtaDriveLs.hpp
@@ -1,6 +1,6 @@
 /*!
  * @project        The CERN Tape Archive (CTA)
- * @brief          CTA Admin Ls stream implementation
+ * @brief          CTA Drive Ls stream implementation
  * @copyright      Copyright 2019 CERN
  * @license        This program is free software: you can redistribute it and/or modify
  *                 it under the terms of the GNU General Public License as published by
diff --git a/xroot_plugins/XrdCtaGroupMountRuleLs.hpp b/xroot_plugins/XrdCtaGroupMountRuleLs.hpp
index e4861d91a24c2d42a3d7c39fe7980334b0716b36..38f27b5c5076574cce45cf3adcf32f91c4aa271f 100644
--- a/xroot_plugins/XrdCtaGroupMountRuleLs.hpp
+++ b/xroot_plugins/XrdCtaGroupMountRuleLs.hpp
@@ -1,6 +1,6 @@
 /*!
  * @project        The CERN Tape Archive (CTA)
- * @brief          CTA Archive Route Ls stream implementation
+ * @brief          CTA Group Mount Rule Ls stream implementation
  * @copyright      Copyright 2019 CERN
  * @license        This program is free software: you can redistribute it and/or modify
  *                 it under the terms of the GNU General Public License as published by
@@ -51,7 +51,7 @@ private:
    */
   virtual int fillBuffer(XrdSsiPb::OStreamBuffer<Data> *streambuf);
 
-  std::list<cta::common::dataStructures::RequesterGroupMountRule> m_groupMountRuleList;    //!< List of archive routes from the catalogue
+  std::list<cta::common::dataStructures::RequesterGroupMountRule> m_groupMountRuleList;    //!< List of group mount rules from the catalogue
 
   static constexpr const char* const LOG_SUFFIX  = "GroupMountRuleLsStream";               //!< Identifier for log messages
 };
diff --git a/xroot_plugins/XrdCtaLogicalLibraryLs.hpp b/xroot_plugins/XrdCtaLogicalLibraryLs.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..7df9a93e69c7e329d6c4cc335fe2053d2ed066ef
--- /dev/null
+++ b/xroot_plugins/XrdCtaLogicalLibraryLs.hpp
@@ -0,0 +1,91 @@
+/*!
+ * @project        The CERN Tape Archive (CTA)
+ * @brief          CTA Logical Library Ls stream implementation
+ * @copyright      Copyright 2019 CERN
+ * @license        This program is free software: you can redistribute it and/or modify
+ *                 it under the terms of the GNU General Public License as published by
+ *                 the Free Software Foundation, either version 3 of the License, or
+ *                 (at your option) any later version.
+ *
+ *                 This program is distributed in the hope that it will be useful,
+ *                 but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *                 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *                 GNU General Public License for more details.
+ *
+ *                 You should have received a copy of the GNU General Public License
+ *                 along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <xroot_plugins/XrdCtaStream.hpp>
+#include <xroot_plugins/XrdSsiCtaRequestMessage.hpp>
+
+
+namespace cta { namespace xrd {
+
+/*!
+ * Stream object which implements "tapepool ls" command
+ */
+class LogicalLibraryLsStream: public XrdCtaStream{
+public:
+  /*!
+   * Constructor
+   *
+   * @param[in]    requestMsg    RequestMessage containing command-line arguments
+   * @param[in]    catalogue     CTA Catalogue
+   * @param[in]    scheduler     CTA Scheduler
+   */
+  LogicalLibraryLsStream(const RequestMessage &requestMsg, cta::catalogue::Catalogue &catalogue, cta::Scheduler &scheduler);
+
+private:
+  /*!
+   * Can we close the stream?
+   */
+  virtual bool isDone() const {
+    return m_logicalLibraryList.empty();
+  }
+
+  /*!
+   * Fill the buffer
+   */
+  virtual int fillBuffer(XrdSsiPb::OStreamBuffer<Data> *streambuf);
+
+  std::list<cta::common::dataStructures::LogicalLibrary> m_logicalLibraryList;    //!< List of logical libraries from the catalogue
+
+  static constexpr const char* const LOG_SUFFIX  = "LogicalLibraryLsStream";      //!< Identifier for log messages
+};
+
+
+LogicalLibraryLsStream::LogicalLibraryLsStream(const RequestMessage &requestMsg, cta::catalogue::Catalogue &catalogue, cta::Scheduler &scheduler) :
+  XrdCtaStream(catalogue, scheduler),
+  m_logicalLibraryList(catalogue.getLogicalLibraries())
+{
+  using namespace cta::admin;
+
+  XrdSsiPb::Log::Msg(XrdSsiPb::Log::DEBUG, LOG_SUFFIX, "LogicalLibraryLsStream() constructor");
+}
+
+int LogicalLibraryLsStream::fillBuffer(XrdSsiPb::OStreamBuffer<Data> *streambuf) {
+  for(bool is_buffer_full = false; !m_logicalLibraryList.empty() && !is_buffer_full; m_logicalLibraryList.pop_front()) {
+    Data record;
+
+    auto &ll      = m_logicalLibraryList.front();
+    auto  ll_item = record.mutable_llls_item();
+
+    ll_item->set_name(ll.name);
+    ll_item->set_is_disabled(ll.isDisabled);
+    ll_item->mutable_creation_log()->set_username(ll.creationLog.username);
+    ll_item->mutable_creation_log()->set_host(ll.creationLog.host);
+    ll_item->mutable_creation_log()->set_time(ll.creationLog.time);
+    ll_item->mutable_last_modification_log()->set_username(ll.lastModificationLog.username);
+    ll_item->mutable_last_modification_log()->set_host(ll.lastModificationLog.host);
+    ll_item->mutable_last_modification_log()->set_time(ll.lastModificationLog.time);
+    ll_item->set_comment(ll.comment);
+
+    is_buffer_full = streambuf->Push(record);
+  }
+  return streambuf->Size();
+}
+
+}} // namespace cta::xrd
diff --git a/xroot_plugins/XrdCtaMountPolicyLs.hpp b/xroot_plugins/XrdCtaMountPolicyLs.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..084bad6086ac3926fdf0cd67e6059a3f82c579f9
--- /dev/null
+++ b/xroot_plugins/XrdCtaMountPolicyLs.hpp
@@ -0,0 +1,95 @@
+/*!
+ * @project        The CERN Tape Archive (CTA)
+ * @brief          CTA Mount Policy Ls stream implementation
+ * @copyright      Copyright 2019 CERN
+ * @license        This program is free software: you can redistribute it and/or modify
+ *                 it under the terms of the GNU General Public License as published by
+ *                 the Free Software Foundation, either version 3 of the License, or
+ *                 (at your option) any later version.
+ *
+ *                 This program is distributed in the hope that it will be useful,
+ *                 but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *                 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *                 GNU General Public License for more details.
+ *
+ *                 You should have received a copy of the GNU General Public License
+ *                 along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <xroot_plugins/XrdCtaStream.hpp>
+#include <xroot_plugins/XrdSsiCtaRequestMessage.hpp>
+
+
+namespace cta { namespace xrd {
+
+/*!
+ * Stream object which implements "tapepool ls" command
+ */
+class MountPolicyLsStream: public XrdCtaStream{
+public:
+  /*!
+   * Constructor
+   *
+   * @param[in]    requestMsg    RequestMessage containing command-line arguments
+   * @param[in]    catalogue     CTA Catalogue
+   * @param[in]    scheduler     CTA Scheduler
+   */
+  MountPolicyLsStream(const RequestMessage &requestMsg, cta::catalogue::Catalogue &catalogue, cta::Scheduler &scheduler);
+
+private:
+  /*!
+   * Can we close the stream?
+   */
+  virtual bool isDone() const {
+    return m_mountPolicyList.empty();
+  }
+
+  /*!
+   * Fill the buffer
+   */
+  virtual int fillBuffer(XrdSsiPb::OStreamBuffer<Data> *streambuf);
+
+  std::list<cta::common::dataStructures::MountPolicy> m_mountPolicyList;     //!< List of mount policies from the catalogue
+
+  static constexpr const char* const LOG_SUFFIX  = "MountPolicyLsStream";    //!< Identifier for log messages
+};
+
+
+MountPolicyLsStream::MountPolicyLsStream(const RequestMessage &requestMsg, cta::catalogue::Catalogue &catalogue, cta::Scheduler &scheduler) :
+  XrdCtaStream(catalogue, scheduler),
+  m_mountPolicyList(catalogue.getMountPolicies())
+{
+  using namespace cta::admin;
+
+  XrdSsiPb::Log::Msg(XrdSsiPb::Log::DEBUG, LOG_SUFFIX, "MountPolicyLsStream() constructor");
+}
+
+int MountPolicyLsStream::fillBuffer(XrdSsiPb::OStreamBuffer<Data> *streambuf) {
+  for(bool is_buffer_full = false; !m_mountPolicyList.empty() && !is_buffer_full; m_mountPolicyList.pop_front()) {
+    Data record;
+
+    auto &mp      = m_mountPolicyList.front();
+    auto  mp_item = record.mutable_mpls_item();
+
+    mp_item->set_name(mp.name);
+    mp_item->set_archive_priority(mp.archivePriority);
+    mp_item->set_archive_min_request_age(mp.archiveMinRequestAge);
+    mp_item->set_retrieve_priority(mp.retrievePriority);
+    mp_item->set_retrieve_min_request_age(mp.retrieveMinRequestAge);
+    mp_item->set_max_drives_allowed(mp.maxDrivesAllowed);
+    mp_item->mutable_creation_log()->set_username(mp.creationLog.username);
+    mp_item->mutable_creation_log()->set_host(mp.creationLog.host);
+    mp_item->mutable_creation_log()->set_time(mp.creationLog.time);
+    mp_item->mutable_last_modification_log()->set_username(mp.lastModificationLog.username);
+    mp_item->mutable_last_modification_log()->set_host(mp.lastModificationLog.host);
+    mp_item->mutable_last_modification_log()->set_time(mp.lastModificationLog.time);
+    mp_item->set_comment(mp.comment);
+
+    is_buffer_full = streambuf->Push(record);
+  }
+  return streambuf->Size();
+}
+
+}} // namespace cta::xrd
diff --git a/xroot_plugins/XrdCtaRequesterMountRuleLs.hpp b/xroot_plugins/XrdCtaRequesterMountRuleLs.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..af455befd1f653a60be5f81926e1a1457996a31e
--- /dev/null
+++ b/xroot_plugins/XrdCtaRequesterMountRuleLs.hpp
@@ -0,0 +1,92 @@
+/*!
+ * @project        The CERN Tape Archive (CTA)
+ * @brief          CTA Requester Mount Rule Ls stream implementation
+ * @copyright      Copyright 2019 CERN
+ * @license        This program is free software: you can redistribute it and/or modify
+ *                 it under the terms of the GNU General Public License as published by
+ *                 the Free Software Foundation, either version 3 of the License, or
+ *                 (at your option) any later version.
+ *
+ *                 This program is distributed in the hope that it will be useful,
+ *                 but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *                 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *                 GNU General Public License for more details.
+ *
+ *                 You should have received a copy of the GNU General Public License
+ *                 along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <xroot_plugins/XrdCtaStream.hpp>
+#include <xroot_plugins/XrdSsiCtaRequestMessage.hpp>
+
+
+namespace cta { namespace xrd {
+
+/*!
+ * Stream object which implements "tapepool ls" command
+ */
+class RequesterMountRuleLsStream: public XrdCtaStream{
+public:
+  /*!
+   * Constructor
+   *
+   * @param[in]    requestMsg    RequestMessage containing command-line arguments
+   * @param[in]    catalogue     CTA Catalogue
+   * @param[in]    scheduler     CTA Scheduler
+   */
+  RequesterMountRuleLsStream(const RequestMessage &requestMsg, cta::catalogue::Catalogue &catalogue, cta::Scheduler &scheduler);
+
+private:
+  /*!
+   * Can we close the stream?
+   */
+  virtual bool isDone() const {
+    return m_requesterMountRuleList.empty();
+  }
+
+  /*!
+   * Fill the buffer
+   */
+  virtual int fillBuffer(XrdSsiPb::OStreamBuffer<Data> *streambuf);
+
+  std::list<cta::common::dataStructures::RequesterMountRule> m_requesterMountRuleList;    //!< List of requester mount rules from the catalogue
+
+  static constexpr const char* const LOG_SUFFIX  = "RequesterMountRuleLsStream";          //!< Identifier for log messages
+};
+
+
+RequesterMountRuleLsStream::RequesterMountRuleLsStream(const RequestMessage &requestMsg, cta::catalogue::Catalogue &catalogue, cta::Scheduler &scheduler) :
+  XrdCtaStream(catalogue, scheduler),
+  m_requesterMountRuleList(catalogue.getRequesterMountRules())
+{
+  using namespace cta::admin;
+
+  XrdSsiPb::Log::Msg(XrdSsiPb::Log::DEBUG, LOG_SUFFIX, "RequesterMountRuleLsStream() constructor");
+}
+
+int RequesterMountRuleLsStream::fillBuffer(XrdSsiPb::OStreamBuffer<Data> *streambuf) {
+  for(bool is_buffer_full = false; !m_requesterMountRuleList.empty() && !is_buffer_full; m_requesterMountRuleList.pop_front()) {
+    Data record;
+
+    auto &rmr      = m_requesterMountRuleList.front();
+    auto  rmr_item = record.mutable_rmrls_item();
+
+    rmr_item->set_disk_instance(rmr.diskInstance);
+    rmr_item->set_requester_mount_rule(rmr.name);
+    rmr_item->set_mount_policy(rmr.mountPolicy);
+    rmr_item->mutable_creation_log()->set_username(rmr.creationLog.username);
+    rmr_item->mutable_creation_log()->set_host(rmr.creationLog.host);
+    rmr_item->mutable_creation_log()->set_time(rmr.creationLog.time);
+    rmr_item->mutable_last_modification_log()->set_username(rmr.lastModificationLog.username);
+    rmr_item->mutable_last_modification_log()->set_host(rmr.lastModificationLog.host);
+    rmr_item->mutable_last_modification_log()->set_time(rmr.lastModificationLog.time);
+    rmr_item->set_comment(rmr.comment);
+
+    is_buffer_full = streambuf->Push(record);
+  }
+  return streambuf->Size();
+}
+
+}} // namespace cta::xrd
diff --git a/xroot_plugins/XrdCtaShowQueues.hpp b/xroot_plugins/XrdCtaShowQueues.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..a6addb3a8f1e5fec70993ca27495046a8c710b41
--- /dev/null
+++ b/xroot_plugins/XrdCtaShowQueues.hpp
@@ -0,0 +1,119 @@
+/*!
+ * @project        The CERN Tape Archive (CTA)
+ * @brief          CTA Show Queues stream implementation
+ * @copyright      Copyright 2019 CERN
+ * @license        This program is free software: you can redistribute it and/or modify
+ *                 it under the terms of the GNU General Public License as published by
+ *                 the Free Software Foundation, either version 3 of the License, or
+ *                 (at your option) any later version.
+ *
+ *                 This program is distributed in the hope that it will be useful,
+ *                 but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *                 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *                 GNU General Public License for more details.
+ *
+ *                 You should have received a copy of the GNU General Public License
+ *                 along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <xroot_plugins/XrdCtaStream.hpp>
+#include <xroot_plugins/XrdSsiCtaRequestMessage.hpp>
+#include <common/dataStructures/MountTypeSerDeser.hpp>
+
+namespace cta { namespace xrd {
+
+/*!
+ * Stream object which implements "tapepool ls" command
+ */
+class ShowQueuesStream: public XrdCtaStream{
+public:
+  /*!
+   * Constructor
+   *
+   * @param[in]    requestMsg    RequestMessage containing command-line arguments
+   * @param[in]    catalogue     CTA Catalogue
+   * @param[in]    scheduler     CTA Scheduler
+   */
+  ShowQueuesStream(const RequestMessage &requestMsg, cta::catalogue::Catalogue &catalogue,
+    cta::Scheduler &scheduler, log::LogContext &lc);
+
+private:
+  /*!
+   * Can we close the stream?
+   */
+  virtual bool isDone() const {
+    return m_queuesAndMountsList.empty();
+  }
+
+  /*!
+   * Fill the buffer
+   */
+  virtual int fillBuffer(XrdSsiPb::OStreamBuffer<Data> *streambuf);
+
+  std::list<cta::common::dataStructures::QueueAndMountSummary> m_queuesAndMountsList;    //!< List of queues and mounts from the scheduler
+
+  static constexpr const char* const LOG_SUFFIX  = "ShowQueuesStream";                   //!< Identifier for log messages
+};
+
+ShowQueuesStream::ShowQueuesStream(const RequestMessage &requestMsg, cta::catalogue::Catalogue &catalogue,
+  cta::Scheduler &scheduler, log::LogContext &lc) :
+  XrdCtaStream(catalogue, scheduler),
+  m_queuesAndMountsList(scheduler.getQueuesAndMountSummaries(lc))
+{
+  using namespace cta::admin;
+
+  XrdSsiPb::Log::Msg(XrdSsiPb::Log::DEBUG, LOG_SUFFIX, "ShowQueuesStream() constructor");
+}
+
+int ShowQueuesStream::fillBuffer(XrdSsiPb::OStreamBuffer<Data> *streambuf) {
+  using namespace cta::admin;
+
+  for(bool is_buffer_full = false; !m_queuesAndMountsList.empty() && !is_buffer_full; m_queuesAndMountsList.pop_front()) {
+    Data record;
+
+    auto &sq      = m_queuesAndMountsList.front();
+    auto  sq_item = record.mutable_sq_item();
+
+    switch(sq.mountType) {
+      case common::dataStructures::MountType::ArchiveForUser:
+        sq_item->set_priority(sq.mountPolicy.archivePriority);
+        sq_item->set_min_age(sq.mountPolicy.archiveMinRequestAge);
+        sq_item->set_max_drives(sq.mountPolicy.maxDrivesAllowed);
+        break;
+      case common::dataStructures::MountType::Retrieve:
+        sq_item->set_priority(sq.mountPolicy.retrievePriority);
+        sq_item->set_min_age(sq.mountPolicy.retrieveMinRequestAge);
+        sq_item->set_max_drives(sq.mountPolicy.maxDrivesAllowed);
+        break;
+      default:
+        break;
+    }
+
+    sq_item->set_mount_type(MountTypeToProtobuf(sq.mountType));
+    sq_item->set_tapepool(sq.tapePool);
+    sq_item->set_logical_library(sq.logicalLibrary);
+    sq_item->set_vid(sq.vid);
+    sq_item->set_queued_files(sq.filesQueued);
+    sq_item->set_queued_bytes(sq.bytesQueued);
+    sq_item->set_oldest_age(sq.oldestJobAge);
+    sq_item->set_cur_mounts(sq.currentMounts);
+    sq_item->set_cur_files(sq.currentFiles);
+    sq_item->set_cur_bytes(sq.currentBytes);
+    sq_item->set_bytes_per_second(sq.latestBandwidth);
+    sq_item->set_next_mounts(sq.nextMounts);
+    sq_item->set_tapes_capacity(sq.tapesCapacity);
+    sq_item->set_tapes_files(sq.filesOnTapes);
+    sq_item->set_tapes_bytes(sq.dataOnTapes);
+    sq_item->set_full_tapes(sq.fullTapes);
+    sq_item->set_empty_tapes(sq.emptyTapes);
+    sq_item->set_disabled_tapes(sq.disabledTapes);
+    sq_item->set_writable_tapes(sq.writableTapes);
+
+    is_buffer_full = streambuf->Push(record);
+  }
+  return streambuf->Size();
+}
+
+}} // namespace cta::xrd
diff --git a/xroot_plugins/XrdCtaStorageClassLs.hpp b/xroot_plugins/XrdCtaStorageClassLs.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..9490f801cfbfa5353d82dd0c61633d5659ea93db
--- /dev/null
+++ b/xroot_plugins/XrdCtaStorageClassLs.hpp
@@ -0,0 +1,92 @@
+/*!
+ * @project        The CERN Tape Archive (CTA)
+ * @brief          CTA Storage Class Ls stream implementation
+ * @copyright      Copyright 2019 CERN
+ * @license        This program is free software: you can redistribute it and/or modify
+ *                 it under the terms of the GNU General Public License as published by
+ *                 the Free Software Foundation, either version 3 of the License, or
+ *                 (at your option) any later version.
+ *
+ *                 This program is distributed in the hope that it will be useful,
+ *                 but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *                 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *                 GNU General Public License for more details.
+ *
+ *                 You should have received a copy of the GNU General Public License
+ *                 along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <xroot_plugins/XrdCtaStream.hpp>
+#include <xroot_plugins/XrdSsiCtaRequestMessage.hpp>
+
+
+namespace cta { namespace xrd {
+
+/*!
+ * Stream object which implements "tapepool ls" command
+ */
+class StorageClassLsStream: public XrdCtaStream{
+public:
+  /*!
+   * Constructor
+   *
+   * @param[in]    requestMsg    RequestMessage containing command-line arguments
+   * @param[in]    catalogue     CTA Catalogue
+   * @param[in]    scheduler     CTA Scheduler
+   */
+  StorageClassLsStream(const RequestMessage &requestMsg, cta::catalogue::Catalogue &catalogue, cta::Scheduler &scheduler);
+
+private:
+  /*!
+   * Can we close the stream?
+   */
+  virtual bool isDone() const {
+    return m_storageClassList.empty();
+  }
+
+  /*!
+   * Fill the buffer
+   */
+  virtual int fillBuffer(XrdSsiPb::OStreamBuffer<Data> *streambuf);
+
+  std::list<cta::common::dataStructures::StorageClass> m_storageClassList;    //!< List of storage classes from the catalogue
+
+  static constexpr const char* const LOG_SUFFIX  = "StorageClassLsStream";    //!< Identifier for log messages
+};
+
+
+StorageClassLsStream::StorageClassLsStream(const RequestMessage &requestMsg, cta::catalogue::Catalogue &catalogue, cta::Scheduler &scheduler) :
+  XrdCtaStream(catalogue, scheduler),
+  m_storageClassList(catalogue.getStorageClasses())
+{
+  using namespace cta::admin;
+
+  XrdSsiPb::Log::Msg(XrdSsiPb::Log::DEBUG, LOG_SUFFIX, "StorageClassLsStream() constructor");
+}
+
+int StorageClassLsStream::fillBuffer(XrdSsiPb::OStreamBuffer<Data> *streambuf) {
+  for(bool is_buffer_full = false; !m_storageClassList.empty() && !is_buffer_full; m_storageClassList.pop_front()) {
+    Data record;
+
+    auto &sc      = m_storageClassList.front();
+    auto  sc_item = record.mutable_scls_item();
+
+    sc_item->set_disk_instance(sc.diskInstance);
+    sc_item->set_name(sc.name);
+    sc_item->set_nb_copies(sc.nbCopies);
+    sc_item->mutable_creation_log()->set_username(sc.creationLog.username);
+    sc_item->mutable_creation_log()->set_host(sc.creationLog.host);
+    sc_item->mutable_creation_log()->set_time(sc.creationLog.time);
+    sc_item->mutable_last_modification_log()->set_username(sc.lastModificationLog.username);
+    sc_item->mutable_last_modification_log()->set_host(sc.lastModificationLog.host);
+    sc_item->mutable_last_modification_log()->set_time(sc.lastModificationLog.time);
+    sc_item->set_comment(sc.comment);
+
+    is_buffer_full = streambuf->Push(record);
+  }
+  return streambuf->Size();
+}
+
+}} // namespace cta::xrd
diff --git a/xroot_plugins/XrdSsiCtaRequestMessage.cpp b/xroot_plugins/XrdSsiCtaRequestMessage.cpp
index a2ee1f7aa4f1914e34df63252d622c4280ccf15d..24c182edf29aa5642d444e3a8e533208994e4903 100644
--- a/xroot_plugins/XrdSsiCtaRequestMessage.cpp
+++ b/xroot_plugins/XrdSsiCtaRequestMessage.cpp
@@ -33,9 +33,12 @@ using XrdSsiPb::PbException;
 #include "XrdCtaFailedRequestLs.hpp"
 #include "XrdCtaGroupMountRuleLs.hpp"
 #include "XrdCtaListPendingQueue.hpp"
+#include "XrdCtaLogicalLibraryLs.hpp"
 #include "XrdCtaRepackLs.hpp"
 #include "XrdCtaRequesterMountRuleLs.hpp"
+#include "XrdCtaShowQueues.hpp"
 #include "XrdCtaTapeLs.hpp"
+#include "XrdCtaStorageClassLs.hpp"
 #include "XrdCtaTapePoolLs.hpp"
 
 namespace cta {
@@ -68,20 +71,6 @@ static std::string timeToString(const time_t &time)
 
 
 
-/*
- * Helper function to convert bytes to Mb and return the result as a string
- */
-static std::string bytesToMbString(uint64_t bytes)
-{
-   long double mBytes = static_cast<long double>(bytes)/(1000.0*1000.0);
-
-   std::ostringstream oss;
-   oss << std::setprecision(2) << std::fixed << mBytes;
-   return oss.str();
-}
-
-
-
 void RequestMessage::process(const cta::xrd::Request &request, cta::xrd::Response &response, XrdSsiStream* &stream)
 {
    // Branch on the Request payload type
@@ -176,7 +165,7 @@ void RequestMessage::process(const cta::xrd::Request &request, cta::xrd::Respons
                processLogicalLibrary_Rm(response);
                break;
             case cmd_pair(AdminCmd::CMD_LOGICALLIBRARY, AdminCmd::SUBCMD_LS):
-               processLogicalLibrary_Ls(response);
+               processLogicalLibrary_Ls(response, stream);
                break;
             case cmd_pair(AdminCmd::CMD_MOUNTPOLICY, AdminCmd::SUBCMD_ADD):
                processMountPolicy_Add(response);
@@ -188,7 +177,7 @@ void RequestMessage::process(const cta::xrd::Request &request, cta::xrd::Respons
                processMountPolicy_Rm(response);
                break;
             case cmd_pair(AdminCmd::CMD_MOUNTPOLICY, AdminCmd::SUBCMD_LS):
-               processMountPolicy_Ls(response);
+               processMountPolicy_Ls(response, stream);
                break;
             case cmd_pair(AdminCmd::CMD_REPACK, AdminCmd::SUBCMD_ADD):
                processRepack_Add(response);
@@ -215,7 +204,7 @@ void RequestMessage::process(const cta::xrd::Request &request, cta::xrd::Respons
                processRequesterMountRule_Ls(response, stream);
                break;
             case cmd_pair(AdminCmd::CMD_SHOWQUEUES, AdminCmd::SUBCMD_NONE):
-               processShowQueues(response);
+               processShowQueues(response, stream);
                break;
             case cmd_pair(AdminCmd::CMD_STORAGECLASS, AdminCmd::SUBCMD_ADD):
                processStorageClass_Add(response);
@@ -227,7 +216,7 @@ void RequestMessage::process(const cta::xrd::Request &request, cta::xrd::Respons
                processStorageClass_Rm(response);
                break;
             case cmd_pair(AdminCmd::CMD_STORAGECLASS, AdminCmd::SUBCMD_LS):
-               processStorageClass_Ls(response);
+               processStorageClass_Ls(response, stream);
                break;
             case cmd_pair(AdminCmd::CMD_TAPE, AdminCmd::SUBCMD_ADD):
                processTape_Add(response);
@@ -1017,34 +1006,15 @@ void RequestMessage::processLogicalLibrary_Rm(cta::xrd::Response &response)
 
 
 
-void RequestMessage::processLogicalLibrary_Ls(cta::xrd::Response &response)
+void RequestMessage::processLogicalLibrary_Ls(cta::xrd::Response &response, XrdSsiStream* &stream)
 {
-   using namespace cta::admin;
-
-   std::stringstream cmdlineOutput;
-
-   std::list<cta::common::dataStructures::LogicalLibrary> list = m_catalogue.getLogicalLibraries();
+  using namespace cta::admin;
 
-   if(!list.empty())
-   {
-      std::vector<std::vector<std::string>> responseTable;
-      std::vector<std::string> header = {
-         "name","disabled","c.user","c.host","c.time","m.user","m.host","m.time","comment"
-      };
-      if(has_flag(OptionBoolean::SHOW_HEADER)) responseTable.push_back(header);    
-      for(auto it = list.cbegin(); it != list.cend(); it++) {
-         std::vector<std::string> currentRow;
-         currentRow.push_back(it->name);
-         currentRow.push_back(std::to_string(it->isDisabled));
-         addLogInfoToResponseRow(currentRow, it->creationLog, it->lastModificationLog);
-         currentRow.push_back(it->comment);
-         responseTable.push_back(currentRow);
-      }
-      cmdlineOutput << formatResponse(responseTable);
-   }
+  // Create a XrdSsi stream object to return the results
+  stream = new LogicalLibraryLsStream(*this, m_catalogue, m_scheduler);
 
-   response.set_message_txt(cmdlineOutput.str());
-   response.set_type(cta::xrd::Response::RSP_SUCCESS);
+  response.set_show_header(HeaderType::LOGICALLIBRARY_LS);
+  response.set_type(cta::xrd::Response::RSP_SUCCESS);
 }
 
 
@@ -1118,39 +1088,15 @@ void RequestMessage::processMountPolicy_Rm(cta::xrd::Response &response)
 
 
 
-void RequestMessage::processMountPolicy_Ls(cta::xrd::Response &response)
+void RequestMessage::processMountPolicy_Ls(cta::xrd::Response &response, XrdSsiStream* &stream)
 {
-   using namespace cta::admin;
-
-   std::stringstream cmdlineOutput;
-
-   std::list<cta::common::dataStructures::MountPolicy> list= m_catalogue.getMountPolicies();
+  using namespace cta::admin;
 
-   if(!list.empty())
-   {
-      std::vector<std::vector<std::string>> responseTable;
-      std::vector<std::string> header = {
-         "mount policy","a.priority","a.minAge","r.priority","r.minAge","max drives","c.user","c.host","c.time","m.user","m.host","m.time","comment"
-      };
-      if(has_flag(OptionBoolean::SHOW_HEADER)) responseTable.push_back(header);    
-      for(auto it = list.cbegin(); it != list.cend(); it++)
-      {
-         std::vector<std::string> currentRow;
-         currentRow.push_back(it->name);
-         currentRow.push_back(std::to_string(static_cast<unsigned long long>(it->archivePriority)));
-         currentRow.push_back(std::to_string(static_cast<unsigned long long>(it->archiveMinRequestAge)));
-         currentRow.push_back(std::to_string(static_cast<unsigned long long>(it->retrievePriority)));
-         currentRow.push_back(std::to_string(static_cast<unsigned long long>(it->retrieveMinRequestAge)));
-         currentRow.push_back(std::to_string(static_cast<unsigned long long>(it->maxDrivesAllowed)));
-         addLogInfoToResponseRow(currentRow, it->creationLog, it->lastModificationLog);
-         currentRow.push_back(it->comment);
-         responseTable.push_back(currentRow);
-      }
-      cmdlineOutput << formatResponse(responseTable);
-   }
+  // Create a XrdSsi stream object to return the results
+  stream = new LogicalLibraryLsStream(*this, m_catalogue, m_scheduler);
 
-   response.set_message_txt(cmdlineOutput.str());
-   response.set_type(cta::xrd::Response::RSP_SUCCESS);
+  response.set_show_header(HeaderType::MOUNTPOLICY_LS);
+  response.set_type(cta::xrd::Response::RSP_SUCCESS);
 }
 
 
@@ -1302,67 +1248,15 @@ void RequestMessage::processRequesterMountRule_Ls(cta::xrd::Response &response,
 
 
 
-void RequestMessage::processShowQueues(cta::xrd::Response &response)
+void RequestMessage::processShowQueues(cta::xrd::Response &response, XrdSsiStream* &stream)
 {
-   using namespace cta::admin;
-
-   std::stringstream cmdlineOutput;
-
-   auto queuesAndMounts = m_scheduler.getQueuesAndMountSummaries(m_lc);
+  using namespace cta::admin;
 
-   if(!queuesAndMounts.empty())
-   {
-      std::vector<std::vector<std::string>> responseTable;
-      std::vector<std::string> header = {
-         "type","tapepool","logical library","vid","files queued","MBytes queued","oldest age","priority",
-         "min age","max drives","cur. mounts","cur. files","cur. MBytes","MB/s","next mounts","tapes capacity",
-         "files on tapes","MBytes on tapes","full tapes","empty tapes","disabled tapes","writables tapes"
-      };
-      if(has_flag(OptionBoolean::SHOW_HEADER)) responseTable.push_back(header);
-      for (auto & q: queuesAndMounts)
-      {
-         const uint64_t MBytes = 1000 * 1000;
-
-         std::vector<std::string> currentRow;
-         currentRow.push_back(common::dataStructures::toString(q.mountType));
-         currentRow.push_back(q.tapePool);
-         currentRow.push_back(q.logicalLibrary);
-         currentRow.push_back(q.vid);
-         currentRow.push_back(std::to_string(q.filesQueued));
-         currentRow.push_back(bytesToMbString(q.bytesQueued));
-         currentRow.push_back(std::to_string(q.oldestJobAge));
-         if (common::dataStructures::MountType::ArchiveForUser == q.mountType) {
-            currentRow.push_back(std::to_string(q.mountPolicy.archivePriority));
-            currentRow.push_back(std::to_string(q.mountPolicy.archiveMinRequestAge));
-            currentRow.push_back(std::to_string(q.mountPolicy.maxDrivesAllowed));
-         } else if (common::dataStructures::MountType::Retrieve == q.mountType) {
-            currentRow.push_back(std::to_string(q.mountPolicy.retrievePriority));
-            currentRow.push_back(std::to_string(q.mountPolicy.retrieveMinRequestAge));
-            currentRow.push_back(std::to_string(q.mountPolicy.maxDrivesAllowed));
-         } else {
-            currentRow.push_back("-");
-            currentRow.push_back("-");
-            currentRow.push_back("-");
-         }
-         currentRow.push_back(std::to_string(q.currentMounts));
-         currentRow.push_back(std::to_string(q.currentFiles));
-         currentRow.push_back(bytesToMbString(q.currentBytes));
-         currentRow.push_back(bytesToMbString(q.latestBandwidth));
-         currentRow.push_back(std::to_string(q.nextMounts));
-         currentRow.push_back(std::to_string(q.tapesCapacity/MBytes));
-         currentRow.push_back(std::to_string(q.filesOnTapes));
-         currentRow.push_back(bytesToMbString(q.dataOnTapes));
-         currentRow.push_back(std::to_string(q.fullTapes));
-         currentRow.push_back(std::to_string(q.emptyTapes));
-         currentRow.push_back(std::to_string(q.disabledTapes));
-         currentRow.push_back(std::to_string(q.writableTapes));
-         responseTable.push_back(currentRow);
-      }
-      cmdlineOutput << formatResponse(responseTable);
-   }
+  // Create a XrdSsi stream object to return the results
+  stream = new ShowQueuesStream(*this, m_catalogue, m_scheduler, m_lc);
 
-   response.set_message_txt(cmdlineOutput.str());
-   response.set_type(cta::xrd::Response::RSP_SUCCESS);
+  response.set_show_header(HeaderType::SHOWQUEUES);
+  response.set_type(cta::xrd::Response::RSP_SUCCESS);
 }
 
 
@@ -1420,35 +1314,15 @@ void RequestMessage::processStorageClass_Rm(cta::xrd::Response &response)
 
 
 
-void RequestMessage::processStorageClass_Ls(cta::xrd::Response &response)
+void RequestMessage::processStorageClass_Ls(cta::xrd::Response &response, XrdSsiStream* &stream)
 {
-   using namespace cta::admin;
-
-   std::stringstream cmdlineOutput;
-
-   std::list<cta::common::dataStructures::StorageClass> list = m_catalogue.getStorageClasses();
+  using namespace cta::admin;
 
-   if(!list.empty())
-   {
-      std::vector<std::vector<std::string>> responseTable;
-      std::vector<std::string> header = {
-         "instance","storage class","number of copies","c.user","c.host","c.time","m.user","m.host","m.time","comment"
-      };
-      if(has_flag(OptionBoolean::SHOW_HEADER)) responseTable.push_back(header);    
-      for(auto it = list.cbegin(); it != list.cend(); it++) {
-         std::vector<std::string> currentRow;
-         currentRow.push_back(it->diskInstance);
-         currentRow.push_back(it->name);
-         currentRow.push_back(std::to_string(static_cast<unsigned long long>(it->nbCopies)));
-         addLogInfoToResponseRow(currentRow, it->creationLog, it->lastModificationLog);
-         currentRow.push_back(it->comment);
-         responseTable.push_back(currentRow);
-      }
-      cmdlineOutput << formatResponse(responseTable);
-   }
+  // Create a XrdSsi stream object to return the results
+  stream = new StorageClassLsStream(*this, m_catalogue, m_scheduler);
 
-   response.set_message_txt(cmdlineOutput.str());
-   response.set_type(cta::xrd::Response::RSP_SUCCESS);
+  response.set_show_header(HeaderType::STORAGECLASS_LS);
+  response.set_type(cta::xrd::Response::RSP_SUCCESS);
 }
 
 
diff --git a/xroot_plugins/XrdSsiCtaRequestMessage.hpp b/xroot_plugins/XrdSsiCtaRequestMessage.hpp
index 06fcc39900ba4518ed171d7980a65d6a24748c53..7cc51a73314a5fdbff9eac9d01c979d4f69fb885 100644
--- a/xroot_plugins/XrdSsiCtaRequestMessage.hpp
+++ b/xroot_plugins/XrdSsiCtaRequestMessage.hpp
@@ -165,22 +165,18 @@ private:
    void processLogicalLibrary_Add    (cta::xrd::Response &response);
    void processLogicalLibrary_Ch     (cta::xrd::Response &response);
    void processLogicalLibrary_Rm     (cta::xrd::Response &response);
-   void processLogicalLibrary_Ls     (cta::xrd::Response &response);
    void processMountPolicy_Add       (cta::xrd::Response &response);
    void processMountPolicy_Ch        (cta::xrd::Response &response);
    void processMountPolicy_Rm        (cta::xrd::Response &response);
-   void processMountPolicy_Ls        (cta::xrd::Response &response);
    void processRepack_Add            (cta::xrd::Response &response);
    void processRepack_Rm             (cta::xrd::Response &response);
    void processRepack_Err            (cta::xrd::Response &response);
    void processRequesterMountRule_Add(cta::xrd::Response &response);
    void processRequesterMountRule_Ch (cta::xrd::Response &response);
    void processRequesterMountRule_Rm (cta::xrd::Response &response);
-   void processShowQueues            (cta::xrd::Response &response);
    void processStorageClass_Add      (cta::xrd::Response &response);
    void processStorageClass_Ch       (cta::xrd::Response &response);
    void processStorageClass_Rm       (cta::xrd::Response &response);
-   void processStorageClass_Ls       (cta::xrd::Response &response);
    void processTape_Add              (cta::xrd::Response &response);
    void processTape_Ch               (cta::xrd::Response &response);
    void processTape_Rm               (cta::xrd::Response &response);
@@ -207,7 +203,11 @@ private:
    admincmdstream_t processGroupMountRule_Ls;
    admincmdstream_t processListPendingArchives;
    admincmdstream_t processListPendingRetrieves;
+   admincmdstream_t processLogicalLibrary_Ls;
+   admincmdstream_t processMountPolicy_Ls;
    admincmdstream_t processRequesterMountRule_Ls;
+   admincmdstream_t processShowQueues;
+   admincmdstream_t processStorageClass_Ls;
    admincmdstream_t processTapePool_Ls;
    admincmdstream_t processTape_Ls;
    admincmdstream_t processRepack_Ls;
diff --git a/xrootd-ssi-protobuf-interface b/xrootd-ssi-protobuf-interface
index 5ff5030b66c1a5737258af799e75a799285cf970..675db778f40173a5c611b8fc11e70616997be040 160000
--- a/xrootd-ssi-protobuf-interface
+++ b/xrootd-ssi-protobuf-interface
@@ -1 +1 @@
-Subproject commit 5ff5030b66c1a5737258af799e75a799285cf970
+Subproject commit 675db778f40173a5c611b8fc11e70616997be040