diff --git a/include/aidge/operator/MetaOperator.hpp b/include/aidge/operator/MetaOperator.hpp
index 09e6c010f51f2c72cf07e0a7c34a8cb3101e2651..fdbf3a181b0fbe7d52ed5c442f077cc7cb0ce8d0 100644
--- a/include/aidge/operator/MetaOperator.hpp
+++ b/include/aidge/operator/MetaOperator.hpp
@@ -90,6 +90,8 @@ public:
         mGraph->setDataType(datatype);
     }
 
+    std::shared_ptr<Attributes> attributes() const override;
+
     Elts_t getNbRequiredData(const IOIndex_t inputIdx) const override;
     Elts_t getNbRequiredProtected(const IOIndex_t inputIdx) const override;
     Elts_t getRequiredMemory(const IOIndex_t outputIdx, const std::vector<DimSize_t> &inputsSize) const override;
diff --git a/include/aidge/utils/Attributes.hpp b/include/aidge/utils/Attributes.hpp
index 7dce3d327d42de15dc2589788b4643742ed1a463..cf71ed0b5953fa1759e04c66311d3d829a603a01 100644
--- a/include/aidge/utils/Attributes.hpp
+++ b/include/aidge/utils/Attributes.hpp
@@ -14,6 +14,9 @@
 
 #include <string>
 #include <set>
+#include <map>
+
+#include "aidge/utils/future_std/any.hpp"
 
 #ifdef PYBIND
 #include <pybind11/pybind11.h>
@@ -63,6 +66,8 @@ public:
     */
     virtual std::set<std::string> getAttrsName() const = 0;
 
+    virtual std::map<std::string, future_std::any> getAttrs() const = 0;
+
 #ifdef PYBIND
     virtual bool hasAttrPy(const std::string& name) const = 0;
 
@@ -84,6 +89,7 @@ public:
     virtual py::dict dict() const = 0;
 
 #endif
+
     virtual ~Attributes() {}
 };
 }
diff --git a/include/aidge/utils/DynamicAttributes.hpp b/include/aidge/utils/DynamicAttributes.hpp
index 651e1ed419a2e63dc8723b6291e8ee2b4f664b07..2e87f41f6ac972b9e2d59ecabbcf80df4340cc6e 100644
--- a/include/aidge/utils/DynamicAttributes.hpp
+++ b/include/aidge/utils/DynamicAttributes.hpp
@@ -39,6 +39,9 @@ namespace Aidge {
 ///\todo managing complex types or excluding non-trivial, non-aggregate types
 class DynamicAttributes : public Attributes {
 public:
+    DynamicAttributes() = default;
+    DynamicAttributes(const std::map<std::string, future_std::any>& attrs): mAttrs(attrs) {}
+
     /**
      * \brief Returning an Attribute identified by its name
      * \tparam T expected Attribute type
@@ -375,6 +378,10 @@ public:
         }
     }
 
+    std::map<std::string, future_std::any> getAttrs() const override {
+        return mAttrs;
+    }
+
     virtual ~DynamicAttributes() {}
 
     friend bool operator<(const DynamicAttributes& lhs, const DynamicAttributes& rhs);
diff --git a/include/aidge/utils/StaticAttributes.hpp b/include/aidge/utils/StaticAttributes.hpp
index 18e75b7cef5a2e9e9568a900f826a31c87012318..414381891ce52046ee7c2df5b82a17e1314773cd 100644
--- a/include/aidge/utils/StaticAttributes.hpp
+++ b/include/aidge/utils/StaticAttributes.hpp
@@ -179,6 +179,12 @@ public:
         return mAttrs;
     }
 
+    virtual std::map<std::string, future_std::any> getAttrs() const override {
+        std::map<std::string, future_std::any> attrs;
+        appendAttr(mAttrs, attrs);
+        return attrs;
+    }
+
     //////////////////////////////////////
     ///     Generic Attributes API
     //////////////////////////////////////
@@ -323,6 +329,15 @@ private:
 
         return false;
     }
+    
+    template<std::size_t I = 0, typename... Tp>
+    inline typename std::enable_if<I == sizeof...(Tp), void>::type appendAttr(const std::tuple<Tp...>& /*t*/, std::map<std::string, future_std::any>& /*attrs*/) const {}
+
+    template<std::size_t I = 0, typename... Tp>
+    inline typename std::enable_if<I < sizeof...(Tp), void>::type appendAttr(const std::tuple<Tp...>& t, std::map<std::string, future_std::any>& attrs) const {
+        attrs.insert(std::make_pair(EnumStrings<ATTRS_ENUM>::data[I], future_std::any(std::get<I>(t))));
+        appendAttr<I + 1, Tp...>(t, attrs);
+    }
 
     std::tuple<T...> mAttrs;
 };
diff --git a/src/operator/MetaOperator.cpp b/src/operator/MetaOperator.cpp
index c830cae0ec9f53862a7f7712bbee1769154dfcfe..aff8bb19f368187b2c3c733a8706208a02484091 100644
--- a/src/operator/MetaOperator.cpp
+++ b/src/operator/MetaOperator.cpp
@@ -18,6 +18,7 @@
 #include "aidge/data/Tensor.hpp"
 #include "aidge/graph/GraphView.hpp"
 #include "aidge/utils/ErrorHandling.hpp"
+#include "aidge/utils/DynamicAttributes.hpp"
 
 Aidge::MetaOperator_Op::MetaOperator_Op(const std::string& type, const std::shared_ptr<GraphView>& graph)
     : OperatorTensor(type, [graph]() {
@@ -81,6 +82,19 @@ void Aidge::MetaOperator_Op::setBackend(const std::string &name, Aidge::DeviceId
     mGraph->setBackend(name, device);
 }
 
+std::shared_ptr<Aidge::Attributes> Aidge::MetaOperator_Op::attributes() const {
+    std::map<std::string, future_std::any> attrs;
+
+    for (const auto& node : mGraph->getNodes()) {
+        const auto nodeAttrs = node->getOperator()->attributes()->getAttrs();
+        for (const auto& attr : nodeAttrs) {
+            attrs.insert(std::make_pair(attr.first, attr.second));
+        }
+    }
+
+    return std::make_shared<DynamicAttributes>(attrs);
+}
+
 Aidge::Elts_t Aidge::MetaOperator_Op::getNbRequiredData(const IOIndex_t inputIdx) const {
     if (mImpl) {
         return mImpl->prodConso()->getNbRequiredData(inputIdx);