diff --git a/force_bdss/base_core_driver.py b/force_bdss/base_core_driver.py
index b3c2702ef10a8e7750dd01fa9ced87a22e2c70c8..5875f1784dd0db5af54adb5b5901aeb869aca1a0 100644
--- a/force_bdss/base_core_driver.py
+++ b/force_bdss/base_core_driver.py
@@ -1,12 +1,10 @@
-from envisage.extension_point import ExtensionPoint
 from envisage.plugin import Plugin
-from traits.api import List
+from traits.trait_types import Instance
 
-from force_bdss.data_sources.i_data_source_bundle import (
-    IDataSourceBundle)
-from force_bdss.kpi.i_kpi_calculator_bundle import IKPICalculatorBundle
-from force_bdss.mco.i_multi_criteria_optimizer_bundle import (
-    IMultiCriteriaOptimizerBundle)
+from force_bdss.bundle_registry_plugin import (
+    BundleRegistryPlugin,
+    BUNDLE_REGISTRY_PLUGIN_ID
+)
 
 
 class BaseCoreDriver(Plugin):
@@ -14,50 +12,7 @@ class BaseCoreDriver(Plugin):
     or the evaluation.
     """
 
-    # Note: we are forced to declare these extensions points here instead
-    # of the application object, and this is why we have to use this plugin.
-    # It is a workaround to an envisage bug that does not find the extension
-    # points if declared on the application.
+    bundle_registry = Instance(BundleRegistryPlugin)
 
-    #: A List of the available Multi Criteria Optimizers.
-    #: This will be populated by MCO plugins.
-    mco_bundles = ExtensionPoint(
-        List(IMultiCriteriaOptimizerBundle),
-        id='force.bdss.mco.bundles')
-
-    #: A list of the available Data Sources.
-    #: It will be populated by plugins.
-    data_source_bundles = ExtensionPoint(
-        List(IDataSourceBundle),
-        id='force.bdss.data_sources.bundles')
-
-    #: A list of the available Key Performance Indicator calculators.
-    #: It will be populated by plugins.
-    kpi_calculator_bundles = ExtensionPoint(
-        List(IKPICalculatorBundle),
-        id='force.bdss.kpi_calculators.bundles')
-
-    def _data_source_bundle_by_id(self, id):
-        for ds in self.data_source_bundles:
-            if ds.id == id:
-                return ds
-
-        raise Exception("Requested data source {} but don't know "
-                        "to find it.".format(id))
-
-    def _kpi_calculator_bundle_by_id(self, id):
-        for kpic in self.kpi_calculator_bundles:
-            if kpic.id == id:
-                return kpic
-
-        raise Exception(
-            "Requested kpi calculator {} but don't know "
-            "to find it.".format(id))
-
-    def _mco_bundle_by_id(self, id):
-        for mco in self.mco_bundles:
-            if mco.id == id:
-                return mco
-
-        raise Exception("Requested MCO {} but it's not available"
-                        "to compute it.".format(id))
+    def _bundle_registry_default(self):
+        return self.application.get_plugin(BUNDLE_REGISTRY_PLUGIN_ID)
diff --git a/force_bdss/bdss_application.py b/force_bdss/bdss_application.py
index a0ac1141945a0ef434a55592bed537bd5011a163..c813e4dc4357c922bc356ef48f076adfc70966be 100644
--- a/force_bdss/bdss_application.py
+++ b/force_bdss/bdss_application.py
@@ -5,6 +5,7 @@ from stevedore.exception import NoMatches
 from envisage.api import Application
 from envisage.core_plugin import CorePlugin
 
+from force_bdss.bundle_registry_plugin import BundleRegistryPlugin
 from force_bdss.core_evaluation_driver import CoreEvaluationDriver
 from force_bdss.core_mco_driver import CoreMCODriver
 
@@ -33,7 +34,7 @@ class BDSSApplication(Application):
         self.evaluate = evaluate
         self.workflow_filepath = workflow_filepath
 
-        plugins = [CorePlugin()]
+        plugins = [CorePlugin(), BundleRegistryPlugin()]
 
         if self.evaluate:
             plugins.append(CoreEvaluationDriver())
diff --git a/force_bdss/bundle_registry_plugin.py b/force_bdss/bundle_registry_plugin.py
new file mode 100644
index 0000000000000000000000000000000000000000..f0e418c72e931bc49bf6600dac65be56dcdde7d0
--- /dev/null
+++ b/force_bdss/bundle_registry_plugin.py
@@ -0,0 +1,107 @@
+from envisage.extension_point import ExtensionPoint
+from envisage.plugin import Plugin
+from traits.api import List
+
+from force_bdss.data_sources.i_data_source_bundle import (
+    IDataSourceBundle)
+from force_bdss.kpi.i_kpi_calculator_bundle import IKPICalculatorBundle
+from force_bdss.mco.i_multi_criteria_optimizer_bundle import (
+    IMultiCriteriaOptimizerBundle)
+
+
+BUNDLE_REGISTRY_PLUGIN_ID = "force.bdss.plugins.bundle_registry"
+
+
+class BundleRegistryPlugin(Plugin):
+    """Main plugin that handles the execution of the MCO
+    or the evaluation.
+    """
+    id = BUNDLE_REGISTRY_PLUGIN_ID
+
+    # Note: we are forced to declare these extensions points here instead
+    # of the application object, and this is why we have to use this plugin.
+    # It is a workaround to an envisage bug that does not find the extension
+    # points if declared on the application.
+
+    #: A List of the available Multi Criteria Optimizers.
+    #: This will be populated by MCO plugins.
+    mco_bundles = ExtensionPoint(
+        List(IMultiCriteriaOptimizerBundle),
+        id='force.bdss.mco.bundles')
+
+    #: A list of the available Data Sources.
+    #: It will be populated by plugins.
+    data_source_bundles = ExtensionPoint(
+        List(IDataSourceBundle),
+        id='force.bdss.data_sources.bundles')
+
+    #: A list of the available Key Performance Indicator calculators.
+    #: It will be populated by plugins.
+    kpi_calculator_bundles = ExtensionPoint(
+        List(IKPICalculatorBundle),
+        id='force.bdss.kpi_calculators.bundles')
+
+    def data_source_bundle_by_id(self, id):
+        """Finds a given data source bundle by means of its id.
+        The ID is as obtained by the function bundle_id() in the
+        plugin api.
+
+        Parameters
+        ----------
+        id: str
+            The identifier returned by the bundle_id() function.
+
+        Raises
+        ------
+        ValueError: if the entry is not found.
+        """
+        for ds in self.data_source_bundles:
+            if ds.id == id:
+                return ds
+
+        raise ValueError(
+            "Requested data source {} but don't know how "
+            "to find it.".format(id))
+
+    def kpi_calculator_bundle_by_id(self, id):
+        """Finds a given kpi bundle by means of its id.
+        The ID is as obtained by the function bundle_id() in the
+        plugin api.
+
+        Parameters
+        ----------
+        id: str
+            The identifier returned by the bundle_id() function.
+
+        Raises
+        ------
+        ValueError: if the entry is not found.
+        """
+        for kpic in self.kpi_calculator_bundles:
+            if kpic.id == id:
+                return kpic
+
+        raise ValueError(
+            "Requested kpi calculator {} but don't know how "
+            "to find it.".format(id))
+
+    def mco_bundle_by_id(self, id):
+        """Finds a given Multi Criteria Optimizer (MCO) bundle by means of
+        its id. The ID is as obtained by the function bundle_id() in the
+        plugin api.
+
+        Parameters
+        ----------
+        id: str
+            The identifier returned by the bundle_id() function.
+
+        Raises
+        ------
+        ValueError: if the entry is not found.
+        """
+        for mco in self.mco_bundles:
+            if mco.id == id:
+                return mco
+
+        raise ValueError("Requested MCO {} but don't know how "
+                         "to find it.".format(id))
diff --git a/force_bdss/core_evaluation_driver.py b/force_bdss/core_evaluation_driver.py
index bf6c848c7b0acf3c400601eaaf19e1c167788bdd..19e56664c580721246ee42ad65197512ccad8e0a 100644
--- a/force_bdss/core_evaluation_driver.py
+++ b/force_bdss/core_evaluation_driver.py
@@ -13,7 +13,7 @@ class CoreEvaluationDriver(BaseCoreDriver):
         workflow = self.application.workflow
 
         mco_data = workflow.multi_criteria_optimizer
-        mco_bundle = self._mco_bundle_by_id(mco_data.id)
+        mco_bundle = self.bundle_registry.mco_bundle_by_id(mco_data.id)
         mco_model = mco_bundle.create_model(mco_data.model_data)
         mco_communicator = mco_bundle.create_communicator(
             self.application,
@@ -23,7 +23,7 @@ class CoreEvaluationDriver(BaseCoreDriver):
 
         ds_results = []
         for requested_ds in workflow.data_sources:
-            ds_bundle = self._data_source_bundle_by_id(
+            ds_bundle = self.bundle_registry.data_source_bundle_by_id(
                 requested_ds.id)
             ds_model = ds_bundle.create_model(requested_ds.model_data)
             data_source = ds_bundle.create_data_source(
@@ -32,7 +32,7 @@ class CoreEvaluationDriver(BaseCoreDriver):
 
         kpi_results = []
         for requested_kpic in workflow.kpi_calculators:
-            kpic_bundle = self._kpi_calculator_bundle_by_id(
+            kpic_bundle = self.bundle_registry.kpi_calculator_bundle_by_id(
                 requested_kpic.id)
             ds_model = kpic_bundle.create_model(
                 requested_kpic.model_data)
diff --git a/force_bdss/core_mco_driver.py b/force_bdss/core_mco_driver.py
index f1cb9b483ac0727f6afcb813d4f0c0c933db836e..6a1321e84587e9bc681dff92d529a3340ab728fb 100644
--- a/force_bdss/core_mco_driver.py
+++ b/force_bdss/core_mco_driver.py
@@ -13,7 +13,7 @@ class CoreMCODriver(BaseCoreDriver):
         workflow = self.application.workflow
 
         mco_data = workflow.multi_criteria_optimizer
-        mco_bundle = self._mco_bundle_by_id(mco_data.id)
+        mco_bundle = self.bundle_registry.mco_bundle_by_id(mco_data.id)
         mco_model = mco_bundle.create_model(mco_data.model_data)
         mco = mco_bundle.create_optimizer(self.application, mco_model)
 
diff --git a/force_bdss/tests/test_bundle_registry_plugin.py b/force_bdss/tests/test_bundle_registry_plugin.py
new file mode 100644
index 0000000000000000000000000000000000000000..f0869f0dc518d1dd26d6e9fd7d4947b8d0209be3
--- /dev/null
+++ b/force_bdss/tests/test_bundle_registry_plugin.py
@@ -0,0 +1,99 @@
+import unittest
+
+from force_bdss.id_generators import bundle_id
+
+try:
+    import mock
+except ImportError:
+    from unittest import mock
+
+from traits.api import List
+from envisage.application import Application
+from envisage.plugin import Plugin
+
+from force_bdss.bundle_registry_plugin import BundleRegistryPlugin
+from force_bdss.data_sources.i_data_source_bundle import IDataSourceBundle
+from force_bdss.kpi.i_kpi_calculator_bundle import IKPICalculatorBundle
+from force_bdss.mco.i_multi_criteria_optimizer_bundle import \
+    IMultiCriteriaOptimizerBundle
+
+
+class TestBundleRegistry(unittest.TestCase):
+    def setUp(self):
+        self.plugin = BundleRegistryPlugin()
+        self.app = Application([self.plugin])
+        self.app.start()
+        self.app.stop()
+
+    def test_initialization(self):
+        self.assertEqual(self.plugin.mco_bundles, [])
+        self.assertEqual(self.plugin.data_source_bundles, [])
+        self.assertEqual(self.plugin.kpi_calculator_bundles, [])
+
+
+class BaseBDSSPlugin(Plugin):
+    mco_bundles = List(
+        IMultiCriteriaOptimizerBundle,
+        contributes_to='force.bdss.mco.bundles'
+    )
+
+    #: A list of the available Data Sources.
+    #: It will be populated by plugins.
+    data_source_bundles = List(
+        IDataSourceBundle,
+        contributes_to='force.bdss.data_sources.bundles')
+
+    kpi_calculator_bundles = List(
+        IKPICalculatorBundle,
+        contributes_to='force.bdss.kpi_calculators.bundles'
+    )
+
+
+class MySuperPlugin(BaseBDSSPlugin):
+    def _mco_bundles_default(self):
+        return [mock.Mock(spec=IMultiCriteriaOptimizerBundle,
+                          id=bundle_id("enthought", "mco1"))]
+
+    def _data_source_bundles_default(self):
+        return [mock.Mock(spec=IDataSourceBundle,
+                          id=bundle_id("enthought", "ds1")),
+                mock.Mock(spec=IDataSourceBundle,
+                          id=bundle_id("enthought", "ds2"))]
+
+    def _kpi_calculator_bundles_default(self):
+        return [mock.Mock(spec=IKPICalculatorBundle,
+                          id=bundle_id("enthought", "kpi1")),
+                mock.Mock(spec=IKPICalculatorBundle,
+                          id=bundle_id("enthought", "kpi2")),
+                mock.Mock(spec=IKPICalculatorBundle,
+                          id=bundle_id("enthought", "kpi3"))]
+
+
+class TestBundleRegistryWithContent(unittest.TestCase):
+    def setUp(self):
+        self.plugin = BundleRegistryPlugin()
+        self.app = Application([self.plugin, MySuperPlugin()])
+        self.app.start()
+        self.app.stop()
+
+    def test_initialization(self):
+        self.assertEqual(len(self.plugin.mco_bundles), 1)
+        self.assertEqual(len(self.plugin.data_source_bundles), 2)
+        self.assertEqual(len(self.plugin.kpi_calculator_bundles), 3)
+
+    def test_lookup(self):
+        id = bundle_id("enthought", "mco1")
+        self.assertEqual(self.plugin.mco_bundle_by_id(id).id, id)
+
+        for entry in ["ds1", "ds2"]:
+            id = bundle_id("enthought", entry)
+            self.assertEqual(self.plugin.data_source_bundle_by_id(id).id, id)
+
+        for entry in ["kpi1", "kpi2", "kpi3"]:
+            id = bundle_id("enthought", entry)
+            self.assertEqual(self.plugin.kpi_calculator_bundle_by_id(id).id,
+                             id)
+
+
+if __name__ == '__main__':
+    unittest.main()