diff --git a/Detector/MP/include/Detector/MP/MPChannelID.h b/Detector/MP/include/Detector/MP/MPChannelID.h
new file mode 100644
index 0000000000000000000000000000000000000000..6cc6646ddd1fbc9c406b2faa27709d44af6aee66
--- /dev/null
+++ b/Detector/MP/include/Detector/MP/MPChannelID.h
@@ -0,0 +1,167 @@
+/*****************************************************************************\
+* (c) Copyright 2000-2019 CERN for the benefit of the LHCb Collaboration      *
+*                                                                             *
+* This software is distributed under the terms of the GNU General Public      *
+* Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING".   *
+*                                                                             *
+* In applying this licence, CERN does not waive the privileges and immunities *
+* granted to it by virtue of its status as an Intergovernmental Organization  *
+* or submit itself to any jurisdiction.                                       *
+\*****************************************************************************/
+#pragma once
+
+#include <array>
+#include <cassert>
+#include <climits>
+#include <cstdint>
+#include <exception>
+#include <fmt/format.h>
+#include <functional>
+#include <iostream>
+#include <type_traits>
+#include <utility>
+
+namespace LHCb::Detector {
+  /** @brief a faked MIGHTY tracker channel ID
+   *
+   * This class encodes a MIGHTY tracker channel ID. It has the following
+   * features:
+   *
+   * - It uses the MCKey of the particle.
+   * - There is no physical meaning to the LHCBID
+   */
+  class MPChannelID final {
+    /// Bitmasks
+    enum struct Mask : unsigned {
+      key         = 0x1ffff, // 00011111111111111111 -> 131071
+      layer       = 0x20000, // 00100000000000000000
+      station     = 0xc0000, // 11000000000000000000
+      uniqueLayer = layer | station,
+    };
+
+    template <Mask m>
+    [[nodiscard]] static constexpr unsigned int extract( unsigned int i ) {
+      constexpr auto b =
+          __builtin_ctz( static_cast<unsigned int>( m ) ); // FIXME: C++20 replace __builtin_ctz with std::countr_zero
+      return ( i & static_cast<unsigned int>( m ) ) >> b;
+    }
+
+    template <Mask m>
+    [[nodiscard]] static constexpr unsigned int shift( unsigned int i ) {
+      constexpr auto b =
+          __builtin_ctz( static_cast<unsigned int>( m ) ); // FIXME: C++20 replace __builtin_ctz with std::countr_zero
+      auto v = ( i << static_cast<unsigned int>( b ) );
+      assert( extract<m>( v ) == i );
+      return v;
+    }
+
+    template <Mask m, typename T>
+    [[nodiscard]] static constexpr unsigned int shift( T i ) {
+      return shift<m>( to_unsigned( i ) );
+    }
+
+  public:
+    enum struct StationID : unsigned int {};
+    [[nodiscard]] friend constexpr unsigned int to_unsigned( StationID id ) { return static_cast<unsigned>( id ); }
+
+    enum struct LayerID : unsigned int {};
+    [[nodiscard]] friend constexpr unsigned int to_unsigned( LayerID id ) { return static_cast<unsigned>( id ); }
+
+    template <typename IDtype>
+    struct to_ID_t {
+      constexpr std::vector<IDtype> operator()( const std::vector<int>& v ) const {
+        std::vector<IDtype> ret;
+        ret.reserve( v.size() );
+        std::transform( v.begin(), v.end(), std::back_inserter( ret ),
+                        []( int a ) { return IDtype{static_cast<unsigned int>( a )}; } );
+        return ret;
+      };
+    };
+
+    static constexpr auto to_stationID = to_ID_t<StationID>{};
+    static constexpr auto to_layerID   = to_ID_t<LayerID>{};
+
+    /// Default Constructor
+    constexpr MPChannelID() = default;
+
+    /// Constructor from int
+    constexpr explicit MPChannelID( unsigned int id ) : m_channelID{id} {}
+
+    /// Explicit constructor from the geometrical location and key
+    constexpr MPChannelID( unsigned int station, unsigned int layer, unsigned int key )
+        : MPChannelID{shift<Mask::station>( station ) | shift<Mask::layer>( layer ) | shift<Mask::key>( key )} {}
+
+    // Operator overload, to cast channel ID to unsigned int. Used by linkers where the key (channel id) is an int
+    constexpr operator unsigned int() const { return m_channelID; }
+
+    /// Comparison equality
+    constexpr friend bool operator==( MPChannelID lhs, MPChannelID rhs ) { return lhs.channelID() == rhs.channelID(); }
+
+    /// Comparison <
+    constexpr friend bool operator<( MPChannelID lhs, MPChannelID rhs ) { return lhs.channelID() < rhs.channelID(); }
+
+    /// Comparison >
+    constexpr friend bool operator>( MPChannelID lhs, MPChannelID rhs ) { return rhs < lhs; }
+
+    /// Increment the channelID
+    constexpr MPChannelID& advance() {
+      ++m_channelID;
+      return *this;
+    }
+
+    /// Retrieve const  MP Channel ID
+    [[nodiscard]] constexpr unsigned int channelID() const { return m_channelID; }
+
+    /// Retrieve MCKey of particle
+    [[nodiscard]] constexpr unsigned int key() const { return extract<Mask::key>( m_channelID ); }
+
+    /// Retrieve Layer id
+    [[nodiscard]] constexpr LayerID layer() const { return LayerID{extract<Mask::layer>( m_channelID )}; }
+
+    /// Retrieve Station id
+    [[nodiscard]] constexpr StationID station() const { return StationID{extract<Mask::station>( m_channelID )}; }
+
+    /// Retrieve unique layer
+    [[nodiscard]] constexpr unsigned int globalLayerID() const { return extract<Mask::uniqueLayer>( m_channelID ); }
+
+    /// Retrieve global station index [0..2]
+    [[nodiscard]] constexpr unsigned int globalStationIdx() const {
+      assert( to_unsigned( station() ) != 0 &&
+              "Trying to get the station idx of a station 0! This typically happens when having a kInvalidChannel." );
+      return to_unsigned( station() ) - 1;
+    }
+
+    /// Retrieve global layer index [0..11]
+    [[nodiscard]] constexpr unsigned int globalLayerIdx() const {
+      return ( 2 * globalStationIdx() + to_unsigned( layer() ) );
+    }
+
+    /// Retrieve local layer Index
+    [[nodiscard]] constexpr unsigned int localLayerIdx() const { return to_unsigned( layer() ); }
+
+    // /// Retrieve channelID for monitoring
+    // [[nodiscard]] constexpr unsigned int key() const {
+    //   return to_unsigned( key() );
+    // }
+
+    friend std::ostream& operator<<( std::ostream& s, const MPChannelID& obj ) {
+      return s << "{ MPChannelID : "
+               << " key =" << obj.key() << " layer=" << to_unsigned( obj.layer() )
+               << " station=" << to_unsigned( obj.station() ) << " }";
+    }
+
+    /// Operator overload, to cast channel ID to std::string
+    friend std::string toString( const MPChannelID& id ) {
+      return fmt::format( "T{}L{}K{}", to_unsigned( id.station() ), to_unsigned( id.layer() ), id.key() );
+    }
+
+    /// Operator overload, to cast channel ID to std::string
+    std::string toString() const {
+      return fmt::format( "T{}L{}K{}", to_unsigned( station() ), to_unsigned( layer() ), key() );
+    }
+
+  private:
+    unsigned int m_channelID{0}; /// MP Channel ID
+
+  }; // class MPChannelID
+} // namespace LHCb::Detector
diff --git a/Detector/MP/include/Detector/MP/MPVolumeID.h b/Detector/MP/include/Detector/MP/MPVolumeID.h
new file mode 100644
index 0000000000000000000000000000000000000000..5d2c2db20c5029262892f9c182b21389f5666394
--- /dev/null
+++ b/Detector/MP/include/Detector/MP/MPVolumeID.h
@@ -0,0 +1,56 @@
+/*****************************************************************************\
+* (c) Copyright 2000-2023 CERN for the benefit of the LHCb Collaboration      *
+*                                                                             *
+* This software is distributed under the terms of the GNU General Public      *
+* Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING".   *
+*                                                                             *
+* In applying this licence, CERN does not waive the privileges and immunities *
+* granted to it by virtue of its status as an Intergovernmental Organization  *
+* or submit itself to any jurisdiction.                                       *
+\*****************************************************************************/
+#pragma once
+
+#include "Detector/MP/MPChannelID.h"
+
+#include <fmt/format.h>
+
+#include <cassert>
+#include <iosfwd>
+
+namespace LHCb::Detector {
+
+  class MPVolumeID final {
+    /// Bitmasks for bitfield volumeID
+    enum struct Mask : unsigned {
+      system  = 0x00000FF, // 0000,0000,0000,0000,0000,1111,1111
+      station = 0x0000F00, // 0000,0000,0000,0000,1111,0000,0000
+      layer   = 0x001F000, // 0000,0000,0001,1111,0000,0000,0000
+      half    = 0x0020000, // 0000,0000,0010,0000,0000,0000,0000
+      module  = 0x0FC0000, // 0000,1111,1100,0000,0000,0000,0000
+      mat     = 0xF000000  // 1111,0000,0000,0000,0000,0000,0000
+    };
+
+    template <Mask m>
+    [[nodiscard]] static constexpr unsigned int extract( unsigned int i ) {
+      constexpr auto b =
+          __builtin_ctz( static_cast<unsigned int>( m ) ); // FIXME: C++20 replace __builtin_ctz with std::countr_zero
+      return ( i & static_cast<unsigned int>( m ) ) >> b;
+    }
+
+  public:
+    unsigned system() const { return extract<Mask::system>( m_volumeID ); }
+    unsigned station() const { return extract<Mask::station>( m_volumeID ); }
+    unsigned layer() const { return extract<Mask::layer>( m_volumeID ); }
+    unsigned half() const { return extract<Mask::half>( m_volumeID ); }
+    unsigned module() const { return extract<Mask::module>( m_volumeID ); }
+    unsigned mat() const { return extract<Mask::mat>( m_volumeID ); }
+
+    MPVolumeID( const unsigned int id ) : m_volumeID( id ) {}
+
+  private:
+    static constexpr unsigned int m_systemID{10}; ///< MP system ID
+    unsigned int                  m_volumeID{0};  ///< the full DD4hep Volume ID
+
+  }; // class MPVolumeID
+
+} // namespace LHCb::Detector