diff --git a/GaudiAlg/include/GaudiAlg/MergingTransformer.h b/GaudiAlg/include/GaudiAlg/MergingTransformer.h
index 6bcc8177eb5133b6adc800b0f5c764c6be3afb5c..c60b1538e5ae5238003f37a00d26bc207d7072a2 100644
--- a/GaudiAlg/include/GaudiAlg/MergingTransformer.h
+++ b/GaudiAlg/include/GaudiAlg/MergingTransformer.h
@@ -279,6 +279,87 @@ namespace Gaudi::Functional {
             },
             Gaudi::Details::Property::ImmediatelyInvokeHandler{true}} {}
 
+  // Many of the same -> N with filter functionality
+  template <typename Signature, typename Traits_ = Traits::BaseClass_t<Gaudi::Algorithm>>
+  struct MergingMultiTransformerFilter;
+
+  template <typename... Outs, typename In, typename Traits_>
+  struct MergingMultiTransformerFilter<std::tuple<Outs...>( vector_of_const_<In> const& ), Traits_>
+      : details::DataHandleMixin<std::tuple<Outs...>, std::tuple<>, Traits_> {
+
+  private:
+    using base_class = details::DataHandleMixin<std::tuple<Outs...>, std::tuple<>, Traits_>;
+
+  public:
+    using KeyValue  = typename base_class::KeyValue;
+    using KeyValues = typename base_class::KeyValues;
+    using OutKeys   = std::array<KeyValue, sizeof...( Outs )>;
+
+    MergingMultiTransformerFilter( std::string const& name, ISvcLocator* locator, KeyValues const& inputs,
+                                   OutKeys const& outputs );
+
+    // accessor to input Locations
+    std::string const& inputLocation( unsigned int n ) const { return m_inputLocations.value()[n]; }
+    unsigned int       inputLocationSize() const { return m_inputLocations.value().size(); }
+
+    // derived classes can NOT implement execute
+    StatusCode execute( EventContext const& ) const override final {
+      vector_of_const_<In> ins;
+      ins.reserve( m_inputs.size() );
+      std::transform( m_inputs.begin(), m_inputs.end(), std::back_inserter( ins ),
+                      details::details2::get_from_handle<In>{} );
+      try {
+        return std::apply(
+                   [&]( auto&... outhandle ) {
+                     GF_SUPPRESS_SPURIOUS_CLANG_WARNING_BEGIN
+                     return std::apply(
+                         [&outhandle...]( bool passed, auto&&... data ) {
+                           ( details::put( outhandle, std::forward<decltype( data )>( data ) ), ... );
+                           return passed;
+                         },
+                         ( *this )( std::as_const( ins ) ) );
+                     GF_SUPPRESS_SPURIOUS_CLANG_WARNING_END
+                   },
+                   this->m_outputs )
+                   ? FilterDecision::PASSED
+                   : FilterDecision::FAILED;
+      } catch ( GaudiException& e ) {
+        ( e.code() ? this->warning() : this->error() ) << e.message() << endmsg;
+        return e.code();
+      }
+    }
+
+    virtual std::tuple<bool, Outs...> operator()( const vector_of_const_<In>& inputs ) const = 0;
+
+  private:
+    // if In is a pointer, it signals optional (as opposed to mandatory) input
+    template <typename T>
+    using InputHandle_t = details::InputHandle_t<Traits_, typename std::remove_pointer<T>::type>;
+    std::vector<InputHandle_t<In>>            m_inputs;         //   and make the handles properties instead...
+    Gaudi::Property<std::vector<std::string>> m_inputLocations; // TODO/FIXME: remove this duplication...
+    // TODO/FIXME: replace vector of string property + call-back with a
+    //             vector<handle> property ... as soon as declareProperty can deal with that.
+  };
+
+  template <typename... Outs, typename In, typename Traits_>
+  MergingMultiTransformerFilter<std::tuple<Outs...>( const vector_of_const_<In>& ),
+                                Traits_>::MergingMultiTransformerFilter( std::string const& name,
+                                                                         ISvcLocator*       pSvcLocator,
+                                                                         KeyValues const&   inputs,
+                                                                         OutKeys const&     outputs )
+      : base_class( name, pSvcLocator, outputs )
+      , m_inputLocations{
+            this, inputs.first, inputs.second,
+            [=]( Gaudi::Details::PropertyBase& ) {
+              this->m_inputs = details::make_vector_of_handles<decltype( this->m_inputs )>( this, m_inputLocations );
+              if ( std::is_pointer_v<In> ) { // handle constructor does not (yet) allow to set
+                                             // optional flag... so do it
+                                             // explicitly here...
+                std::for_each( this->m_inputs.begin(), this->m_inputs.end(), []( auto& h ) { h.setOptional( true ); } );
+              }
+            },
+            Gaudi::Details::Property::ImmediatelyInvokeHandler{true}} {}
+
 } // namespace Gaudi::Functional
 
 #endif
diff --git a/GaudiExamples/options/FunctionalAlgorithms/MultiMergers.py b/GaudiExamples/options/FunctionalAlgorithms/MultiMergers.py
new file mode 100644
index 0000000000000000000000000000000000000000..e80b0953c20a87fdc935250f6179b280b9ec1ce6
--- /dev/null
+++ b/GaudiExamples/options/FunctionalAlgorithms/MultiMergers.py
@@ -0,0 +1,56 @@
+#####################################################################################
+# (c) Copyright 2021 CERN for the benefit of the LHCb and ATLAS collaborations      #
+#                                                                                   #
+# This software is distributed under the terms of the Apache version 2 licence,     #
+# copied verbatim in the file "LICENSE".                                            #
+#                                                                                   #
+# 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.                                             #
+#####################################################################################
+from Configurables import (
+    ApplicationMgr,
+    EvtStoreSvc,
+    Gaudi__Examples__IntDataProducer as IntDataProducer,
+    is2ff_merger,
+    is2ff_merger_filter,
+)
+
+int_a = IntDataProducer("IntAProducer", Value=2, OutputLocation="/Event/IntA")
+int_b = IntDataProducer("IntBProducer", Value=3, OutputLocation="/Event/IntB")
+merger = is2ff_merger(
+    InputInts=[str(int_a.OutputLocation),
+               str(int_b.OutputLocation)])
+# This filter should set its status to 'passed' as 2 * 2 * 3 > 10
+merger_filter_passing = is2ff_merger_filter(
+    "MergerFilterPassing",
+    InputInts=[
+        str(int_a.OutputLocation),
+        str(int_a.OutputLocation),
+        str(int_b.OutputLocation),
+    ],
+    O1="/Event/MF/Float1",
+    O2="/Event/MF/Float2")
+# This filter should set its status to 'failed' as 2 * 3 < 10
+merger_filter_failing = is2ff_merger_filter(
+    "MergerFilterFailing",
+    InputInts=[
+        str(int_a.OutputLocation),
+        str(int_b.OutputLocation),
+    ],
+    O1="/Event/MFSwapped/Float1",
+    O2="/Event/MFSwapped/Float2")
+
+app = ApplicationMgr(
+    EvtMax=2,
+    EvtSel="NONE",
+    ExtSvc=[EvtStoreSvc("EventDataSvc")],
+    HistogramPersistency="NONE",
+    TopAlg=[
+        int_a,
+        int_b,
+        merger,
+        merger_filter_passing,
+        merger_filter_failing,
+    ],
+)
diff --git a/GaudiExamples/src/FunctionalAlgorithms/MakeAndConsume.cpp b/GaudiExamples/src/FunctionalAlgorithms/MakeAndConsume.cpp
index fe9b1c4ccd5610c914ca55d7b156319c03a1ec3c..a31c6fed5e14d44cbdd8141b4b07ec5c33f24dde 100644
--- a/GaudiExamples/src/FunctionalAlgorithms/MakeAndConsume.cpp
+++ b/GaudiExamples/src/FunctionalAlgorithms/MakeAndConsume.cpp
@@ -52,9 +52,11 @@ namespace Gaudi::Examples {
         : Producer( name, svcLoc, KeyValue( "OutputLocation", "/Event/MyInt" ) ) {}
 
     int operator()() const override {
-      info() << "executing IntDataProducer, storing 7 into " << outputLocation() << endmsg;
-      return 7;
+      info() << "executing IntDataProducer, storing " << m_value.value() << " into " << outputLocation() << endmsg;
+      return m_value;
     }
+
+    Gaudi::Property<int> m_value{this, "Value", 7, "The integer value to produce."};
   };
 
   DECLARE_COMPONENT( IntDataProducer )
diff --git a/GaudiExamples/src/FunctionalAlgorithms/merging_transformer.cpp b/GaudiExamples/src/FunctionalAlgorithms/merging_transformer.cpp
index dcab536b962145392e1d45f65e780eb9e7a5efd5..729e01192cbde3f440ce9b8dd4eb48886b00d3be 100644
--- a/GaudiExamples/src/FunctionalAlgorithms/merging_transformer.cpp
+++ b/GaudiExamples/src/FunctionalAlgorithms/merging_transformer.cpp
@@ -11,9 +11,11 @@
 #include "GaudiAlg/MergingTransformer.h"
 #include <string>
 
-using ints              = Gaudi::Functional::vector_of_const_<int>;
-using out_t             = std::tuple<float, float>;
-using is2ff_merger_base = Gaudi::Functional::MergingMultiTransformer<out_t( ints const& )>;
+using ints                     = Gaudi::Functional::vector_of_const_<int>;
+using out_t                    = std::tuple<float, float>;
+using is2ff_merger_base        = Gaudi::Functional::MergingMultiTransformer<out_t( ints const& )>;
+using is2ff_merger_filter_base = Gaudi::Functional::MergingMultiTransformerFilter<out_t( ints const& )>;
+using filter_out_t             = std::tuple<bool, float, float>;
 
 struct is2ff_merger : public is2ff_merger_base {
   is2ff_merger( std::string const& name, ISvcLocator* pSvcLocator )
@@ -24,13 +26,35 @@ struct is2ff_merger : public is2ff_merger_base {
     float f1 = 1, f2 = 1;
 
     for ( auto i : is ) {
-      info() << "i: " << i;
+      info() << "i: " << i << " ";
       f1 *= i;
       f2 *= 1.f / i;
     }
     info() << endmsg;
-    return out_t{f1, f2};
+    return {f1, f2};
   }
 };
 
 DECLARE_COMPONENT( is2ff_merger )
+
+struct is2ff_merger_filter : public is2ff_merger_filter_base {
+  is2ff_merger_filter( std::string const& name, ISvcLocator* pSvcLocator )
+      : is2ff_merger_filter_base( name, pSvcLocator, {"InputInts", {"firstInt", "secondInt"}},
+                                  {KeyValue{"O1", "firstFloat"}, KeyValue{"O2", "secondFloat"}} ) {}
+
+  filter_out_t operator()( ints const& is ) const override {
+    float f1 = 1, f2 = 1;
+
+    for ( auto i : is ) {
+      info() << "i: " << i << " ";
+      f1 *= i;
+      f2 *= 1.f / i;
+    }
+    info() << endmsg;
+    auto filter_passed = f1 > 10;
+    info() << "Filter " << ( filter_passed ? "passed" : "failed" ) << endmsg;
+    return {filter_passed, f1, f2};
+  }
+};
+
+DECLARE_COMPONENT( is2ff_merger_filter )
diff --git a/GaudiExamples/tests/qmtest/gaudiexamples.qms/functional_algorithms.qms/multi_mergers.qmt b/GaudiExamples/tests/qmtest/gaudiexamples.qms/functional_algorithms.qms/multi_mergers.qmt
new file mode 100644
index 0000000000000000000000000000000000000000..810aa03f2a40ea19e758fa715a01f21a144f9e07
--- /dev/null
+++ b/GaudiExamples/tests/qmtest/gaudiexamples.qms/functional_algorithms.qms/multi_mergers.qmt
@@ -0,0 +1,17 @@
+<?xml version="1.0" ?><!DOCTYPE extension  PUBLIC '-//QM/2.3/Extension//EN'  'http://www.codesourcery.com/qm/dtds/2.3/-//qm/2.3/extension//en.dtd'>
+<!--
+    (c) Copyright 2021 CERN for the benefit of the LHCb and ATLAS collaborations
+
+    This software is distributed under the terms of the Apache version 2 licence,
+    copied verbatim in the file "LICENSE".
+
+    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.
+-->
+<extension class="GaudiTest.GaudiExeTest" kind="test">
+<argument name="program"><text>gaudirun.py</text></argument>
+<argument name="args"><set><text>../../options/FunctionalAlgorithms/MultiMergers.py</text></set></argument>
+  <argument name="use_temp_dir"><enumeral>true</enumeral></argument>
+  <argument name="reference"><text>refs/MultiMergers.ref</text></argument>
+</extension>
diff --git a/GaudiExamples/tests/qmtest/refs/MultiMergers.ref b/GaudiExamples/tests/qmtest/refs/MultiMergers.ref
new file mode 100644
index 0000000000000000000000000000000000000000..b95f492fb458719d1e88f402c2747376a7ac3f5c
--- /dev/null
+++ b/GaudiExamples/tests/qmtest/refs/MultiMergers.ref
@@ -0,0 +1,30 @@
+# --> Including file '/home/apearce/stack-g/Gaudi/GaudiExamples/options/FunctionalAlgorithms/MultiMergers.py'
+# <-- End of file '/home/apearce/stack-g/Gaudi/GaudiExamples/options/FunctionalAlgorithms/MultiMergers.py'
+ApplicationMgr    SUCCESS
+====================================================================================================================================
+                                                   Welcome to ApplicationMgr (GaudiCoreSvc v35r3)
+                                          running on lbquantaperf01 on Fri Apr 30 10:45:07 2021
+====================================================================================================================================
+ApplicationMgr       INFO Application Manager Configured successfully
+EventLoopMgr      WARNING Unable to locate service "EventSelector"
+EventLoopMgr      WARNING No events will be processed from external input.
+ApplicationMgr       INFO Application Manager Initialized successfully
+ApplicationMgr       INFO Application Manager Started successfully
+IntAProducer         INFO executing IntDataProducer, storing 2 into /Event/IntA
+IntBProducer         INFO executing IntDataProducer, storing 3 into /Event/IntB
+is2ff_merger         INFO i: 2 i: 3
+MergerFilterPas...   INFO i: 2 i: 2 i: 3
+MergerFilterPas...   INFO Filter passed
+MergerFilterFai...   INFO i: 2 i: 3
+MergerFilterFai...   INFO Filter failed
+IntAProducer         INFO executing IntDataProducer, storing 2 into /Event/IntA
+IntBProducer         INFO executing IntDataProducer, storing 3 into /Event/IntB
+is2ff_merger         INFO i: 2 i: 3
+MergerFilterPas...   INFO i: 2 i: 2 i: 3
+MergerFilterPas...   INFO Filter passed
+MergerFilterFai...   INFO i: 2 i: 3
+MergerFilterFai...   INFO Filter failed
+ApplicationMgr       INFO Application Manager Stopped successfully
+EventLoopMgr         INFO Histograms converted successfully according to request.
+ApplicationMgr       INFO Application Manager Finalized successfully
+ApplicationMgr       INFO Application Manager Terminated successfully