diff --git a/algo/detectors/much/MuchReadoutConfig.cxx b/algo/detectors/much/MuchReadoutConfig.cxx
index 5d06b3295049d8ed0b7cf85f1ee4f6e2ea1544bd..08336576d88166e472b0709efc56eb8104c7701f 100644
--- a/algo/detectors/much/MuchReadoutConfig.cxx
+++ b/algo/detectors/much/MuchReadoutConfig.cxx
@@ -41,6 +41,49 @@ void MuchReadoutConfig::putParams(FairParamList* l)
 }
 */
 
+  // ---  Constructor  ------------------------------------------------------------------
+  MuchReadoutConfig::MuchReadoutConfig() { Init(); }
+  // ------------------------------------------------------------------------------------
+
+
+  // ---   Destructor   -----------------------------------------------------------------
+  MuchReadoutConfig::~MuchReadoutConfig() {}
+  // ------------------------------------------------------------------------------------
+
+  // ---   Equipment IDs   --------------------------------------------------------------
+  std::vector<uint16_t> MuchReadoutConfig::GetEquipmentIds()
+  {
+    std::vector<uint16_t> result;
+    for (auto& entry : fReadoutMap)
+      result.push_back(entry.first);
+    return result;
+  }
+  // ------------------------------------------------------------------------------------
+
+  // ---   Number of elinks for a component / equipment   -------------------------------
+  size_t MuchReadoutConfig::GetNumElinks(uint16_t equipmentId)
+  {
+    size_t result = 0;
+    auto it       = fReadoutMap.find(equipmentId);
+    if (it != fReadoutMap.end()) result = fReadoutMap[equipmentId].size();
+    return result;
+  }
+  // ------------------------------------------------------------------------------------
+
+
+  // ---  Mapping (equimentId, elink) -> address[channel]  ------------------------------
+  std::vector<uint32_t> MuchReadoutConfig::Map(uint16_t equipmentId, uint16_t elinkId)
+  {
+    std::vector<uint32_t> result;
+    auto equipIter = fReadoutMap.find(equipmentId);
+    if (equipIter != fReadoutMap.end()) {
+      if (elinkId < equipIter->second.size()) { result = equipIter->second.at(elinkId); }
+    }
+    return result;
+  }
+  // ------------------------------------------------------------------------------------
+
+
   void MuchReadoutConfig::Init()
   {
     // This here refers to the mCBM 2021 setup.
diff --git a/algo/detectors/much/MuchReadoutConfig.h b/algo/detectors/much/MuchReadoutConfig.h
index debbabbe805dd0c71a1413443d0f1bbf0d370c3f..50f309fd6b0c97c10a91306da4f99f22547c45a2 100644
--- a/algo/detectors/much/MuchReadoutConfig.h
+++ b/algo/detectors/much/MuchReadoutConfig.h
@@ -20,11 +20,29 @@ namespace cbm::algo
   class MuchReadoutConfig {
 
   public:
-    /** Standard constructor **/
-    MuchReadoutConfig() {};
-
-    /** Destructor **/
-    ~MuchReadoutConfig() {};
+    /** @brief Constructor **/
+    MuchReadoutConfig();
+
+    /** @brief Destructor **/
+    virtual ~MuchReadoutConfig();
+
+    /** @brief Equipment in the configuration
+     ** @return Vector of equipment IDs
+     **/
+    std::vector<uint16_t> GetEquipmentIds();
+
+    /** @brief Number of elinks of a component
+     ** @param Equipment ID
+     ** @return Number of elinks
+     **/
+    size_t GetNumElinks(uint16_t equipmentId);
+
+    /** @brief API: Mapping from component and elink to addresses per channel
+     ** @param equipId     Equipment identifier (component)
+     ** @param elink       Elink number within component
+     ** @return Vector of MUCH addresses, indexed via channel number
+     */
+    std::vector<uint32_t> Map(uint16_t equipId, uint16_t elink);
 
     uint16_t GetNrOfCrobs() { return numComp * numCrobPerComp; }
     uint16_t GetNrOfFebs() { return GetNrOfCrobs() * kuNbFebsPerCrob; }
diff --git a/algo/detectors/much/UnpackMuch.cxx b/algo/detectors/much/UnpackMuch.cxx
index c7daa77b09d12b912043129c65cc706e39ec7a16..9f0937facc365059b63e8da4ff0bfe8e3809fe51 100644
--- a/algo/detectors/much/UnpackMuch.cxx
+++ b/algo/detectors/much/UnpackMuch.cxx
@@ -95,7 +95,7 @@ namespace cbm::algo
   inline void UnpackMuch::ProcessHitMessage(const stsxyter::Message& message, vector<CbmMuchDigi>& digiVec,
                                             UnpackMuchMonitorData& monitor) const
   {
-
+    /* STS version
     // --- Check eLink and get parameters
     uint16_t elink = message.GetLinkIndexHitBinning();
     if (elink >= fParams.fElinkParams.size()) {
@@ -130,7 +130,8 @@ namespace cbm::algo
     double charge = elinkPar.fAdcOffset + (message.GetHitAdc() - 1) * elinkPar.fAdcGain;
 
     // --- Create output digi
-    //  digiVec.emplace_back(address, channel, messageTime, charge);
+    digiVec.emplace_back(address, channel, messageTime, charge);
+*/
   }
   // --------------------------------------------------------------------------
 
diff --git a/algo/detectors/much/UnpackMuch.h b/algo/detectors/much/UnpackMuch.h
index 22bc306fddbf4d954e938566080539539f424143..c6f3f2334471a677cc75c8a1feb1a493fb0f4152 100644
--- a/algo/detectors/much/UnpackMuch.h
+++ b/algo/detectors/much/UnpackMuch.h
@@ -29,11 +29,11 @@ namespace cbm::algo
    ** @brief STS Unpacking parameters for one eLink / ASIC
    **/
   struct UnpackMuchElinkPar {
-    int32_t fAddress     = 0;   ///< CbmMuchAddress for the connected module
-    uint32_t fAsicNr     = 0;   ///< Number of connected ASIC within the module
+    std::vector<uint32_t> fAddress;  ///< CbmMuchAddress for different channels
+    //uint32_t fAsicNr     = 0;   ///< Number of connected ASIC within the module
     uint64_t fTimeOffset = 0.;  ///< Time calibration parameter
-    double fAdcOffset    = 0.;  ///< Charge calibration parameter
-    double fAdcGain      = 0.;  ///< Charge calibration parameter
+    //double fAdcOffset    = 0.;  ///< Charge calibration parameter
+    //double fAdcGain      = 0.;  ///< Charge calibration parameter
   };
 
 
diff --git a/reco/tasks/CMakeLists.txt b/reco/tasks/CMakeLists.txt
index 9b517ee4dca205ed584cb66f3a954061881dbcff..97edf5cb386d3f2ddd3e09c3355d64a5e3169cef 100644
--- a/reco/tasks/CMakeLists.txt
+++ b/reco/tasks/CMakeLists.txt
@@ -39,7 +39,7 @@ ${CBMROOT_SOURCE_DIR}/core/data/raw
 ${CBMROOT_SOURCE_DIR}/algo/evbuild
 ${CBMROOT_SOURCE_DIR}/algo/trigger
 ${CBMROOT_SOURCE_DIR}/algo/detectors/sts
-
+${CBMROOT_SOURCE_DIR}/algo/detectors/much
 )
 
 set(SYSTEM_INCLUDE_DIRECTORIES
diff --git a/reco/tasks/CbmTaskUnpack.cxx b/reco/tasks/CbmTaskUnpack.cxx
index 0d38ae69265e5060f1b30249fa6fb0e7beb1a60a..a692c31167758a30ab61d2a88de489ad18c1ee3f 100644
--- a/reco/tasks/CbmTaskUnpack.cxx
+++ b/reco/tasks/CbmTaskUnpack.cxx
@@ -35,10 +35,11 @@
 
 
 using namespace std;
+using cbm::algo::UnpackMuchElinkPar;
+using cbm::algo::UnpackMuchPar;
 using cbm::algo::UnpackStsElinkPar;
 using cbm::algo::UnpackStsPar;
 
-
 // -----   Constructor   -----------------------------------------------------
 CbmTaskUnpack::CbmTaskUnpack() : FairTask("Unpack") {}
 // ---------------------------------------------------------------------------
@@ -76,7 +77,16 @@ void CbmTaskUnpack::Exec(Option_t*)
 #pragma omp parallel for schedule(dynamic) shared(timeslice) reduction(+ : numMs, numBytes, numDigis, numCompUsed)
   for (uint64_t comp = 0; comp < timeslice->num_components(); comp++) {
 
+    // --- Component log
+    size_t numBytesInComp = 0;
+    size_t numDigisInComp = 0;
+    uint64_t numMsInComp  = 0;
+
+    TStopwatch compTimer;
+    compTimer.Start();
+
     auto systemId = static_cast<fles::SubsystemIdentifier>(timeslice->descriptor(comp, 0).sys_id);
+
     if (systemId == fles::SubsystemIdentifier::STS) {
       const uint16_t equipmentId = timeslice->descriptor(comp, 0).eq_id;
       const auto algoIt          = fAlgoSts.find(equipmentId);
@@ -88,14 +98,8 @@ void CbmTaskUnpack::Exec(Option_t*)
       // algorithms depending on the version.
       assert(timeslice->descriptor(comp, 0).sys_ver == 0x20);
 
-      // --- Component log
-      size_t numBytesInComp = 0;
-      size_t numDigisInComp = 0;
-      TStopwatch compTimer;
-      compTimer.Start();
-
       // --- Microslice loop
-      uint64_t numMsInComp = timeslice->num_microslices(comp);
+      numMsInComp = timeslice->num_microslices(comp);
       for (uint64_t mslice = 0; mslice < numMsInComp; mslice++) {
         const auto msDescriptor = timeslice->descriptor(comp, mslice);
         const auto msContent    = timeslice->content(comp, mslice);
@@ -111,17 +115,48 @@ void CbmTaskUnpack::Exec(Option_t*)
         fTimeslice->fData.fSts.fDigis.insert(fTimeslice->fData.fSts.fDigis.end(), result.first.begin(),
                                              result.first.end());
       }  //# microslice
+      numCompUsed++;
+    }  // system STS
+
+    if (systemId == fles::SubsystemIdentifier::MUCH) {
+      const uint16_t equipmentId = timeslice->descriptor(comp, 0).eq_id;
+      const auto algoIt          = fAlgoMuch.find(equipmentId);
+      assert(algoIt != fAlgoMuch.end());
+
+      // The current algorithm works for the MUCH data format version XXXX (insert) used in XXXX.
+      // Other versions are not yet supported.
+      // In the future, different data formats will be supported by instantiating different
+      // algorithms depending on the version.
+      // assert(timeslice->descriptor(comp, 0).sys_ver == 0x20);    // set for MUCH
 
-      compTimer.Stop();
-      LOG(debug) << GetName() << ": Component " << comp << ", microslices " << numMsInComp << " input size "
-                 << numBytesInComp << " bytes, "
-                 << ", digis " << numDigisInComp << ", CPU time " << compTimer.CpuTime() * 1000. << " ms";
+      // --- Microslice loop
+      numMsInComp = timeslice->num_microslices(comp);
+      for (uint64_t mslice = 0; mslice < numMsInComp; mslice++) {
+        const auto msDescriptor = timeslice->descriptor(comp, mslice);
+        const auto msContent    = timeslice->content(comp, mslice);
+        numBytesInComp += msDescriptor.size;
+        auto result = (algoIt->second)(msContent, msDescriptor, timeslice->start_time());
+        LOG(debug1) << GetName() << ": Component " << comp << ", microslice " << mslice << ", digis "
+                    << result.first.size() << ", errors " << result.second.fNumNonHitOrTsbMessage << " | "
+                    << result.second.fNumErrElinkOutOfRange << " | " << result.second.fNumErrInvalidFirstMessage
+                    << " | " << result.second.fNumErrInvalidMsSize << " | " << result.second.fNumErrTimestampOverflow
+                    << " | ";
+        numDigisInComp += result.first.size();
+#pragma omp critical(insert_much_digis)
+        fTimeslice->fData.fMuch.fDigis.insert(fTimeslice->fData.fMuch.fDigis.end(), result.first.begin(),
+                                              result.first.end());
+      }  //# microslice
       numCompUsed++;
-      numBytes += numBytesInComp;
-      numDigis += numDigisInComp;
-      numMs += numMsInComp;
+    }  // system MUCH
 
-    }  //? system (only STS)
+    compTimer.Stop();
+    LOG(debug) << GetName() << ": Component " << comp << ", microslices " << numMsInComp << " input size "
+               << numBytesInComp << " bytes, "
+               << ", digis " << numDigisInComp << ", CPU time " << compTimer.CpuTime() * 1000. << " ms";
+
+    numBytes += numBytesInComp;
+    numDigis += numDigisInComp;
+    numMs += numMsInComp;
 
   }  //# component
 
@@ -129,9 +164,13 @@ void CbmTaskUnpack::Exec(Option_t*)
 #ifdef WITH_EXECUTION
   std::sort(std::execution::par_unseq, fTimeslice->fData.fSts.fDigis.begin(), fTimeslice->fData.fSts.fDigis.end(),
             [](CbmStsDigi digi1, CbmStsDigi digi2) { return digi1.GetTime() < digi2.GetTime(); });
+  std::sort(std::execution::par_unseq, fTimeslice->fData.fMuch.fDigis.begin(), fTimeslice->fData.fMuch.fDigis.end(),
+            [](CbmMuchDigi digi1, CbmMuchDigi digi2) { return digi1.GetTime() < digi2.GetTime(); });
 #else
   std::sort(fTimeslice->fData.fSts.fDigis.begin(), fTimeslice->fData.fSts.fDigis.end(),
             [](CbmStsDigi digi1, CbmStsDigi digi2) { return digi1.GetTime() < digi2.GetTime(); });
+  std::sort(fTimeslice->fData.fMuch.fDigis.begin(), fTimeslice->fData.fMuch.fDigis.end(),
+            [](CbmMuchDigi digi1, CbmMuchDigi digi2) { return digi1.GetTime() < digi2.GetTime(); });
 #endif
 
   // --- Timeslice log
@@ -202,16 +241,16 @@ InitStatus CbmTaskUnpack::Init()
   ioman->RegisterAny("DigiTimeslice.", fTimeslice, IsOutputBranchPersistent("DigiTimeslice."));
   LOG(info) << "--- Registered branch DigiTimeslice.";
 
-  // --- Common parameters for all components
-  uint32_t numChansPerAsic   = 128;  // R/O channels per ASIC
-  uint32_t numAsicsPerModule = 16;   // Number of ASICs per module
+  // --- Common parameters for all components for STS
+  uint32_t numChansPerAsicSts   = 128;  // R/O channels per ASIC for STS
+  uint32_t numAsicsPerModuleSts = 16;   // Number of ASICs per module for STS
 
-  // Create one algorithm per component and configure it with parameters
-  auto equipIds = fStsConfig.GetEquipmentIds();
-  for (auto& equip : equipIds) {
+  // Create one algorithm per component for STS and configure it with parameters
+  auto equipIdsSts = fStsConfig.GetEquipmentIds();
+  for (auto& equip : equipIdsSts) {
     std::unique_ptr<UnpackStsPar> par(new UnpackStsPar());
-    par->fNumChansPerAsic   = numChansPerAsic;
-    par->fNumAsicsPerModule = numAsicsPerModule;
+    par->fNumChansPerAsic   = numChansPerAsicSts;
+    par->fNumAsicsPerModule = numAsicsPerModuleSts;
     const size_t numElinks  = fStsConfig.GetNumElinks(equip);
     for (size_t elink = 0; elink < numElinks; elink++) {
       UnpackStsElinkPar elinkPar;
@@ -228,6 +267,24 @@ InitStatus CbmTaskUnpack::Init()
     LOG(info) << "--- Configured equipment " << equip << " with " << numElinks << " elinks";
   }  //# equipments
 
+  // --- Common parameters for all components for MUCH
+  uint32_t numChansPerAsicMuch = 128;  // R/O channels per ASIC for MUCH
+
+  // Create one algorithm per component and configure it with parameters
+  auto equipIdsMuch = fMuchConfig.GetEquipmentIds();
+  for (auto& equip : equipIdsMuch) {
+    std::unique_ptr<UnpackMuchPar> par(new UnpackMuchPar());
+    par->fNumChansPerAsic  = numChansPerAsicMuch;
+    const size_t numElinks = fMuchConfig.GetNumElinks(equip);
+    for (size_t elink = 0; elink < numElinks; elink++) {
+      UnpackMuchElinkPar elinkPar;
+      elinkPar.fAddress    = fMuchConfig.Map(equip, elink);  // Vector of MUCH addresses for this elink
+      elinkPar.fTimeOffset = 0.;
+    }
+    fAlgoMuch[equip].SetParams(std::move(par));
+    LOG(info) << "--- Configured equipment " << equip << " with " << numElinks << " elinks";
+  }
+
   LOG(info) << "--- Configured " << fAlgoSts.size() << " unpacker algorithms for STS.";
   LOG(debug) << "Readout map:" << fStsConfig.PrintReadoutMap();
   LOG(info) << "==================================================";
diff --git a/reco/tasks/CbmTaskUnpack.h b/reco/tasks/CbmTaskUnpack.h
index 541a749a7bbbcc286d98b8e339aadf5362d498e3..940ee17c3378af45ceffe641bcaf5039d6ff82d6 100644
--- a/reco/tasks/CbmTaskUnpack.h
+++ b/reco/tasks/CbmTaskUnpack.h
@@ -15,7 +15,9 @@
 #include <vector>
 
 #include "EventBuilder.h"
+#include "MuchReadoutConfig.h"
 #include "StsReadoutConfig.h"
+#include "UnpackMuch.h"
 #include "UnpackSts.h"
 
 class CbmDigiManager;
@@ -67,9 +69,14 @@ private:  // methods
 
 
 private:  // members
-  CbmSourceTs* fSource                              = nullptr;
+  CbmSourceTs* fSource = nullptr;
+
   std::map<uint16_t, cbm::algo::UnpackSts> fAlgoSts = {};
   cbm::algo::StsReadoutConfig fStsConfig {};
+
+  std::map<uint16_t, cbm::algo::UnpackMuch> fAlgoMuch = {};
+  cbm::algo::MuchReadoutConfig fMuchConfig {};
+
   size_t fNumTs                = 0;
   size_t fNumMs                = 0;
   size_t fNumBytes             = 0;