diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 457f38aa6b2e9d6c898a759e821fdf5e06326bd9..5696287e9b2c56096146c67fe0d891548a0abfd4 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -2,6 +2,7 @@ set(HEADERS
     swcio.hpp
     )
 set(BASE_SOURCES
+    parameter_list.cpp
     swcio.cpp
     cell.cpp
 )
diff --git a/src/parameter_list.cpp b/src/parameter_list.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..4394e800b32137501f3fc48b57ee573898926cad
--- /dev/null
+++ b/src/parameter_list.cpp
@@ -0,0 +1,99 @@
+#include <algorithm>
+#include <iostream>
+
+#include "parameter_list.hpp"
+
+namespace nestmc {
+
+    bool parameter_list::add_parameter(parameter p)
+    {
+        if(has_parameter(p.name)) {
+            return false;
+        }
+
+        parameters_.push_back(std::move(p));
+
+        return true;
+    }
+
+    bool parameter_list::has_parameter(std::string const& n) const
+    {
+        return find_by_name(n) != parameters_.end();
+    }
+
+    int parameter_list::num_parameters() const
+    {
+        return parameters_.size();
+    }
+
+    // returns true if parameter was succesfully updated
+    // returns false if parameter was not updated, i.e. if
+    //  - no parameter with name n exists
+    //  - value is not in the valid range
+    bool parameter_list::set(std::string const& n, parameter_list::value_type v)
+    {
+        auto p = find_by_name(n);
+        if(p!=parameters_.end()) {
+            if(p->is_in_range(v)) {
+                p->value = v;
+                return true;
+            }
+        }
+        return false;
+    }
+
+    parameter& parameter_list::get(std::string const& n)
+    {
+        return *find_by_name(n);
+    }
+
+    std::string const& parameter_list::name() const {
+        return mechanism_name_;
+    }
+
+    std::vector<parameter> const& parameter_list::parameters() const
+    {
+        return parameters_;
+    }
+
+    auto parameter_list::find_by_name(std::string const& n)
+        -> decltype(parameters_.begin())
+    {
+        return
+            std::find_if(
+                parameters_.begin(), parameters_.end(),
+                [&n](parameter const& p) {return p.name == n;}
+            );
+    }
+
+    auto parameter_list::find_by_name(std::string const& n) const
+        -> decltype(parameters_.begin())
+    {
+        return
+            std::find_if(
+                parameters_.begin(), parameters_.end(),
+                [&n](parameter const& p) {return p.name == n;}
+            );
+    }
+
+
+    std::ostream& operator<<(std::ostream& o, parameter const& p)
+    {
+        return o
+            << "parameter("
+            << "name " << p.name
+            << " : value " << p.value
+            << " : range " << p.range
+            << ")";
+    }
+
+    std::ostream& operator<<(std::ostream& o, parameter_list const& l)
+    {
+        o << "parameters \"" << l.name() << "\" :\n";
+        for(auto const& p : l.parameters()) {
+            o << "  " << p << "\n";
+        }
+        return o;
+    }
+
+} // namespace nestmc
diff --git a/src/parameter_list.hpp b/src/parameter_list.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..ef790a640d40264585c1dcdb25c9d917a72624bb
--- /dev/null
+++ b/src/parameter_list.hpp
@@ -0,0 +1,163 @@
+#pragma once
+
+#include <limits>
+#include <ostream>
+#include <stdexcept>
+#include <string>
+#include <vector>
+
+namespace nestmc {
+
+    template <typename T>
+    struct value_range {
+        using value_type = T;
+
+        value_range()
+        :   min(std::numeric_limits<value_type>::quiet_NaN()),
+            max(std::numeric_limits<value_type>::quiet_NaN())
+        { }
+
+        value_range(value_type const& left, value_type const& right)
+        :   min(left),
+            max(right)
+        {
+            if(left>right) {
+                throw std::out_of_range(
+                    "parameter range must have left <= right"
+                );
+            }
+        }
+
+        bool has_lower_bound() const
+        {
+            return min==min;
+        }
+
+        bool has_upper_bound() const
+        {
+            return max==max;
+        }
+
+        bool is_in_range(value_type const& v) const
+        {
+            if(has_lower_bound()) {
+                if(v<min) return false;
+            }
+            if(has_upper_bound()) {
+                if(v>max) return false;
+            }
+            return true;
+        }
+
+        value_type min;
+        value_type max;
+    };
+
+    template <typename T>
+    std::ostream& operator<<(std::ostream& o, value_range<T> const& r)
+    {
+        return
+            o << "[ "
+              << (r.has_lower_bound() ? std::to_string(r.min) : "-inf") << ", "
+              << (r.has_upper_bound() ? std::to_string(r.max) : "inf") << "]";
+    }
+
+    struct parameter {
+        using value_type = double;
+        using range_type = value_range<value_type>;
+
+        parameter() = delete;
+
+        parameter(std::string n, value_type v, range_type r=range_type())
+        :   name(std::move(n)),
+            value(v),
+            range(r)
+        {
+            if(!is_in_range(v)) {
+                throw std::out_of_range(
+                    "parameter value is out of permitted value range"
+                );
+            }
+        }
+
+        bool is_in_range(value_type v) const
+        {
+            return range.is_in_range(v);
+        }
+
+        std::string name;
+        value_type value;
+        range_type range;
+    };
+
+    std::ostream& operator<<(std::ostream& o, parameter const& p);
+
+    // Use a dumb container class for now
+    // might have to use a more sophisticated interface in the future if need be
+    class parameter_list {
+        public :
+
+        using value_type = double;
+
+        parameter_list(std::string n)
+        : mechanism_name_(std::move(n))
+        { }
+
+        bool has_parameter(std::string const& n) const;
+        bool add_parameter(parameter p);
+
+        // returns true if parameter was succesfully updated
+        // returns false if parameter was not updated, i.e. if
+        //  - no parameter with name n exists
+        //  - value is not in the valid range
+        bool set(std::string const& n, value_type v);
+        parameter& get(std::string const& n);
+
+        std::string const& name() const;
+
+        std::vector<parameter> const& parameters() const;
+
+        int num_parameters() const;
+
+        private:
+
+        std::vector<parameter> parameters_;
+        std::string mechanism_name_;
+
+        // need two versions for const and non-const applications
+        auto find_by_name(std::string const& n)
+            -> decltype(parameters_.begin());
+
+        auto find_by_name(std::string const& n) const
+            -> decltype(parameters_.begin());
+
+    };
+
+    std::ostream& operator<<(std::ostream& o, parameter_list const& l);
+
+    class hh_parameters
+    : public parameter_list
+    {
+        public:
+
+        using base = parameter_list;
+
+        using base::value_type;
+
+        using base::set;
+        using base::get;
+        using base::parameters;
+        using base::has_parameter;
+
+        hh_parameters()
+        : base("hh")
+        {
+            base::add_parameter({"gnabar", 0.12,  {0., 1e9}});
+            base::add_parameter({"gkbar",  0.036, {0., 1e9}});
+            base::add_parameter({"gl",     0.0003,{0., 1e9}});
+            base::add_parameter({"el",     -54.3});
+        }
+    };
+
+} // namespace nestmc
+
diff --git a/src/segment.hpp b/src/segment.hpp
index a2429032f28d97aa61f87eb31f79b9783eca4246..ca7251b898ec8800ec71711777bcd44863e618f7 100644
--- a/src/segment.hpp
+++ b/src/segment.hpp
@@ -5,6 +5,7 @@
 #include <vector>
 
 #include "math.hpp"
+#include "parameter_list.hpp"
 #include "point.hpp"
 #include "util.hpp"
 
@@ -76,9 +77,40 @@ class segment {
 
     segment_properties<value_type> properties;
 
+    void add_mechanism(parameter_list p)
+    {
+        auto it = std::find_if(
+            mechanisms_.begin(), mechanisms_.end(),
+            [&p](parameter_list const& l){return l.name() == p.name();}
+        );
+        if(it!=mechanisms_.end()) {
+            throw std::out_of_range(
+                "attempt to add a mechanism parameter set to a segment which has an existing mechanism with the same name"
+            );
+        }
+
+        mechanisms_.push_back(std::move(p));
+    }
+
+    parameter_list& mechanism(std::string const& n)
+    {
+        auto it = std::find_if(
+            mechanisms_.begin(), mechanisms_.end(),
+            [&n](parameter_list const& l){return l.name() == n;}
+        );
+        if(it==mechanisms_.end()) {
+            throw std::out_of_range(
+                "attempt to access a parameter that is not defined in a segment"
+            );
+        }
+
+        return *it;
+    }
+
     protected:
 
     segmentKind kind_;
+    std::vector<parameter_list> mechanisms_;
 };
 
 class placeholder_segment : public segment
diff --git a/tests/test_run.cpp b/tests/test_run.cpp
index f80cb41f612d2fd53db9162ec6b8400634cf91bc..618d9e79560ea0764d7c22ec844749dc8ec51ffa 100644
--- a/tests/test_run.cpp
+++ b/tests/test_run.cpp
@@ -15,25 +15,69 @@ TEST(run, init)
 
     EXPECT_EQ(cell.graph().num_segments(), 2u);
 
+    /*
     for(auto &s : cell.segments()) {
         std::cout << "volume : " << s->volume()
                   << " area : " << s->area()
                   << " ratio : " << s->volume()/s->area() << std::endl;
     }
-
-#ifdef example_1
+    */
 
     // in this context (i.e. attached to a segment on a high-level cell)
     // a mechanism is essentially a set of parameters
     // - the only "state" is that used to define parameters
-    cell.soma()->add_mechanism("hh");
+    cell.soma()->add_mechanism(hh_parameters());
+
+    auto& soma_hh = cell.soma()->mechanism("hh");
 
-    auto& soma_hh = cell.soma()->mechanisms("hh");
     soma_hh.set("gnabar", 0.12);
     soma_hh.set("gkbar", 0.036);
     soma_hh.set("gl", 0.0003);
     soma_hh.set("el", -54.3);
 
-    fvm_cell fv(cell);
-#endif
+    // check that parameter values were set correctly
+    EXPECT_EQ(cell.soma()->mechanism("hh").get("gnabar").value, 0.12);
+    EXPECT_EQ(cell.soma()->mechanism("hh").get("gkbar").value, 0.036);
+    EXPECT_EQ(cell.soma()->mechanism("hh").get("gl").value, 0.0003);
+    EXPECT_EQ(cell.soma()->mechanism("hh").get("el").value, -54.3);
+
+    // print out the parameters if you want...
+    //std::cout << soma_hh << "\n";
+
+}
+
+// test out the parameter infrastructure
+TEST(run, parameters)
+{
+    nestmc::parameter_list list("test");
+    EXPECT_EQ(list.name(), "test");
+    EXPECT_EQ(list.num_parameters(), 0);
+
+    nestmc::parameter p("a", 0.12, {0, 10});
+
+    // add_parameter() returns a bool that indicates whether
+    // it was able to successfull add the parameter
+    EXPECT_EQ(list.add_parameter(std::move(p)), true);
+    EXPECT_EQ(list.num_parameters(), 1u);
+
+    // test in place construction of a parameter
+    EXPECT_EQ(list.add_parameter({"b", -3.0}), true);
+    EXPECT_EQ(list.num_parameters(), 2u);
+
+    // check that adding a parameter that already exists returns false
+    // and does not increase the number of parameters
+    EXPECT_EQ(list.add_parameter({"b", -3.0}), false);
+    EXPECT_EQ(list.num_parameters(), 2u);
+
+    auto &parms = list.parameters();
+    EXPECT_EQ(parms[0].name, "a");
+    EXPECT_EQ(parms[0].value, 0.12);
+    EXPECT_EQ(parms[0].range.min, 0);
+    EXPECT_EQ(parms[0].range.max, 10);
+
+    EXPECT_EQ(parms[1].name, "b");
+    EXPECT_EQ(parms[1].value, -3);
+    EXPECT_EQ(parms[1].range.has_lower_bound(), false);
+    EXPECT_EQ(parms[1].range.has_upper_bound(), false);
 }
+