diff --git a/jupyter-openbis-extension/.server.py.swp b/jupyter-openbis-extension/.server.py.swp
new file mode 100644
index 0000000000000000000000000000000000000000..c294c69447df13190139740612a621e8cc044143
Binary files /dev/null and b/jupyter-openbis-extension/.server.py.swp differ
diff --git a/jupyter-openbis-extension/__init__.py b/jupyter-openbis-extension/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/jupyter-openbis-extension/__pycache__/__init__.cpython-36.pyc b/jupyter-openbis-extension/__pycache__/__init__.cpython-36.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..17c85d6c830fc23516d571d3b9fbc90fd636a634
Binary files /dev/null and b/jupyter-openbis-extension/__pycache__/__init__.cpython-36.pyc differ
diff --git a/jupyter-openbis-extension/__pycache__/extension.cpython-36.pyc b/jupyter-openbis-extension/__pycache__/extension.cpython-36.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..d5f03417cffd6d3922495cb9dca6bf4efab96353
Binary files /dev/null and b/jupyter-openbis-extension/__pycache__/extension.cpython-36.pyc differ
diff --git a/jupyter-openbis-extension/__pycache__/server.cpython-36.pyc b/jupyter-openbis-extension/__pycache__/server.cpython-36.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..0a1e17fe0c786f4007391b5c58e6c6c99190b531
Binary files /dev/null and b/jupyter-openbis-extension/__pycache__/server.cpython-36.pyc differ
diff --git a/jupyter-openbis-extension/server.py b/jupyter-openbis-extension/server.py
new file mode 100644
index 0000000000000000000000000000000000000000..8a6781c7fc2b90b8518cfc8b2ce59e4c405934cc
--- /dev/null
+++ b/jupyter-openbis-extension/server.py
@@ -0,0 +1,238 @@
+from notebook.utils import url_path_join
+from notebook.base.handlers import IPythonHandler
+from pybis import Openbis
+
+import json
+import os
+import urllib
+from subprocess import check_output
+from urllib.parse import urlsplit, urlunsplit
+import yaml
+
+openbis_connections = {}
+
+
+def _jupyter_server_extension_paths():
+    return [{'module': 'jupyter-openbis-extension.server'}]
+
+def _load_configuration(filename='openbis-connections.yaml'):
+    
+    home = os.path.expanduser("~")
+    abs_filename = os.path.join(home, '.jupyter', filename)
+
+    with open(abs_filename, 'r') as stream:
+        try:
+            config = yaml.safe_load(stream)
+            return config
+        except yaml.YAMLexception as exc:
+            print(exc)
+            return None
+        
+
+def load_jupyter_server_extension(nb_server_app):
+    """Call when the extension is loaded.
+    :param nb_server_app: Handle to the Notebook webserver instance.
+    """
+
+    # load the configuration file
+    config = _load_configuration()
+    if config is not None:
+        for conn in config['connections']:
+            try:
+                register_connection(conn)
+            except Exception as exc:
+                print(exc)
+            
+
+    web_app = nb_server_app.web_app
+    host_pattern = '.*$'
+
+    base_url = web_app.settings['base_url']
+
+    web_app.add_handlers(
+        host_pattern, 
+        [(url_path_join(
+            base_url,
+            '/openbis/dataset/(?P<connection_name>.*)?/(?P<permId>.*)'), 
+            DataSetHandler
+        )]
+    ) 
+    web_app.add_handlers(
+        host_pattern, 
+        [(url_path_join(
+            base_url,
+            '/openbis/sample/(?P<connection_name>.*)?/(?P<permId>.*)'), 
+            SampleHandler
+        )]
+    ) 
+    web_app.add_handlers(
+        host_pattern, 
+        [(url_path_join(base_url, '/openbis/conn'), OpenBISHandler)]
+    )
+
+
+    print("pybis loaded: {}".format(Openbis))
+
+
+def register_connection(connection_info):
+    
+    conn = OpenBISConnection(
+        name           = connection_info['name'],
+        url            = connection_info['url'],
+        verify_certificates = connection_info['verify_certificates'],
+        username       = connection_info['username'],
+        password       = connection_info['password'],
+        status         = 'not connected',
+    )
+    openbis_connections[conn.name] = conn
+
+    openbis = Openbis(
+        url = conn.url,
+        verify_certificates = conn.verify_certificates
+    )
+    conn.openbis = openbis
+
+    try:
+        openbis.login(
+            username = conn.username,
+            password = conn.password
+        )
+        conn.status  = 'connected'
+    except Exception as exc:
+        conn.status  = 'FAILED: {}'.format(exc)
+        raise exc
+
+
+def check_connection(connection_name):
+    """Checks whether connection is valid and session is still active
+    and tries to reconnect, if possible. Returns the active session
+    """
+    
+    if connection_name not in openbis_connections:
+        return None
+        
+    conn = openbis_connections[connection_name]
+    if not conn.openbis.isSessionActive():
+        conn.openbis.login(conn.username, conn.password)
+         
+
+class OpenBISConnection:
+    """register an openBIS connection
+    """
+
+    def __init__(self, **kwargs):
+        for key in kwargs:
+            setattr(self, key, kwargs[key])
+
+    def is_session_active(self):
+        return self.openbis.is_session_active()
+
+    def reconnect(self):
+        openbis.login(self.username, self.password)
+
+
+class OpenBISHandler(IPythonHandler):
+    """Handle the requests to /openbis/conn
+    """
+
+    def get(self):
+        """returns all available openBIS connections
+        """
+        connections= []
+        for conn in openbis_connections.values():
+            connections.append({
+                'name': conn.name,
+                'url' : conn.url
+            })
+
+        self.write({
+            'connections': connections 
+        })
+        return
+
+class SampleHandler(IPythonHandler):
+    """Handle the requests for /openbis/sample/connection/permId"""
+
+    def get_datasets(self, conn, permId):
+        sample = None
+        try:
+            sample = conn.openbis.get_sample(permId)
+        except Exception:
+            self.send_error(
+                reason = 'No such sample found: {}'.format(permId)
+            )
+            return
+
+        datasets = sample.get_datasets().df
+        dataset_records = datasets.to_dict(orient='records')
+        self.write({'dataSets': dataset_records })
+        return
+
+    def get(self, **params):
+        """Handle a request to /openbis/sample/connection_name/permId
+        download the data and return a message
+        """
+        try:
+            conn = openbis_connections[params['connection_name']]
+        except KeyError:
+            self.send_error(
+                reason = 'connection {} was not found'.format(params['connection_name'])
+            )
+            return
+        
+        results = self.get_datasets(conn, params['permId'])
+
+
+class DataSetHandler(IPythonHandler):
+    """Handle the requests for /openbis/dataset/connection/permId"""
+
+
+    def download_data(self, conn, permId):
+        if not conn.is_session_active():
+            try:
+                conn.reconnect()
+            except Exception as exc:
+                self.send_error(
+                    reason = 'connection to {} could not be established: {}'.format(conn.name, exc)
+                )
+                return
+
+        try:
+            dataset = conn.openbis.get_dataset(permId)
+        except Exception as exc:
+            self.send_error(
+                reason = 'No such dataSet found: {}'.format(permId)
+            )
+            return
+
+        # dataset was found, download the data to the disk
+        try: 
+            destination = dataset.download()
+        except Exception as exc:
+            print(exc)
+            self.send_error(
+                reason = 'Data for DataSet {} could not be downloaded: {}'.format(permId, exc)
+            )
+            return
+            
+        # return success message
+        path = os.path.join(destination, dataset.permId)
+        self.write({
+            'permId'    : dataset.permId,
+            'statusText': 'Data for DataSet {} was successfully downloaded to {}.'.format(dataset.permId, path)
+        })
+
+    def get(self, **params):
+        """Handle a request to /openbis/dataset/connection_name/permId
+        download the data and return a message
+        """
+        try:
+            conn = openbis_connections[params['connection_name']]
+        except KeyError:
+            self.send_error(
+                reason = 'connection {} was not found'.format(params['connection_name'])
+            )
+            return
+        
+        results = self.download_data(conn, params['permId'])
+