diff --git a/src/pathcomp/frontend/service/algorithms/KDisjointPathAlgorithm.py b/src/pathcomp/frontend/service/algorithms/KDisjointPathAlgorithm.py
index f949383c70f3f2f88a4a5559f2d535e2dbf96775..1e676b0aec93d083217bd53ca8e078b00ddf8376 100644
--- a/src/pathcomp/frontend/service/algorithms/KDisjointPathAlgorithm.py
+++ b/src/pathcomp/frontend/service/algorithms/KDisjointPathAlgorithm.py
@@ -13,7 +13,8 @@
 # limitations under the License.
 
 import copy
-from typing import Optional
+from typing import Dict, List, Optional, Set, Tuple
+from common.proto.context_pb2 import Link
 from common.proto.pathcomp_pb2 import Algorithm_KDisjointPath, Algorithm_KShortestPath, PathCompReply
 from ._Algorithm import _Algorithm
 from .KShortestPathAlgorithm import KShortestPathAlgorithm
@@ -23,6 +24,36 @@ class KDisjointPathAlgorithm(_Algorithm):
         super().__init__('KDP', False, class_name=class_name)
         self.num_disjoint = algorithm.num_disjoint
 
+    def get_link_from_endpoint(self, endpoint : Dict) -> Tuple[Dict, Link]:
+        device_uuid = endpoint['device_id']
+        endpoint_uuid = endpoint['endpoint_uuid']
+        item = self.endpoint_to_link_dict.get((device_uuid, endpoint_uuid))
+        if item is None:
+            MSG = 'Link for Endpoint({:s}, {:s}) not found'
+            self.logger.warning(MSG.format(device_uuid, endpoint_uuid))
+            return None
+        return item
+
+    def path_to_links(self, path_endpoints : List[Dict]) -> Tuple[List[Dict], Set[str]]:
+        path_links = list()
+        path_link_ids = set()
+        for endpoint in path_endpoints:
+            link_tuple = self.get_link_from_endpoint(endpoint)
+            if link_tuple is None: continue
+            json_link,_ = link_tuple
+            json_link_id = json_link['link_Id']
+            if len(path_links) == 0 or path_links[-1]['link_Id'] != json_link_id:
+                path_links.append(json_link)
+                path_link_ids.add(json_link_id)
+        return path_links, path_link_ids
+
+    def remove_traversed_links(self, link_list : List[Dict], path_endpoints : List[Dict]):
+        _, path_link_ids = self.path_to_links(path_endpoints)
+        new_link_list = list(filter(lambda l: l['link_Id'] not in path_link_ids, link_list))
+        self.logger.info('cur_link_list = {:s}'.format(str(link_list)))
+        self.logger.info('new_link_list = {:s}'.format(str(new_link_list)))
+        return new_link_list
+
     def execute(self, dump_request_filename: Optional[str] = None, dump_reply_filename: Optional[str] = None) -> None:
         algorithm = KShortestPathAlgorithm(Algorithm_KShortestPath(k_inspection=0, k_return=1))
         algorithm.sync_paths = True
@@ -35,49 +66,38 @@ class KDisjointPathAlgorithm(_Algorithm):
         algorithm.service_list = self.service_list
         algorithm.service_dict = self.service_dict
 
-        disjoint_paths = dict()
+        Path = List[Dict]
+        Path_NoPath = Optional[Path] # None = no path, list = path
+        self.json_reply : Dict[Tuple[str, str], List[Path_NoPath]] = dict()
 
         for num_path in range(self.num_disjoint):
-            algorithm.execute('ksp-{:d}-request.json'.format(num_path), 'ksp-{:d}-reply.txt'.format(num_path))
+            #dump_request_filename = 'ksp-{:d}-request.json'.format(num_path)
+            #dump_reply_filename   = 'ksp-{:d}-reply.txt'.format(num_path)
+            #algorithm.execute(dump_request_filename, dump_reply_filename)
+            algorithm.execute()
             response_list = algorithm.json_reply.get('response-list', [])
             for response in response_list:
                 service_id = response['serviceId']
                 service_key = (service_id['contextId'], service_id['service_uuid'])
-                disjoint_paths_service = disjoint_paths.setdefault(service_key, list())
+                json_reply_service = self.json_reply.setdefault(service_key, list())
 
                 no_path_issue = response.get('noPath', {}).get('issue')
                 if no_path_issue is not None:
-                    disjoint_paths_service.append(None)
+                    json_reply_service.append(None)
                     continue
 
                 path_endpoints = response['path'][0]['devices']
-                path_links = list()
-                path_link_ids = set()
-                for endpoint in path_endpoints:
-                    device_uuid = endpoint['device_id']
-                    endpoint_uuid = endpoint['endpoint_uuid']
-                    item = algorithm.endpoint_to_link_dict.get((device_uuid, endpoint_uuid))
-                    if item is None:
-                        MSG = 'Link for Endpoint({:s}, {:s}) not found'
-                        self.logger.warning(MSG.format(device_uuid, endpoint_uuid))
-                        continue
-                    json_link,_ = item
-                    json_link_id = json_link['link_Id']
-                    if len(path_links) == 0 or path_links[-1]['link_Id'] != json_link_id:
-                        path_links.append(json_link)
-                        path_link_ids.add(json_link_id)
-                self.logger.info('path_links = {:s}'.format(str(path_links)))
-                disjoint_paths_service.append(path_links)
-
-                new_link_list = list(filter(lambda l: l['link_Id'] not in path_link_ids, algorithm.link_list))
-                self.logger.info('algorithm.link_list = {:s}'.format(str(algorithm.link_list)))
-                self.logger.info('new_link_list = {:s}'.format(str(new_link_list)))
-                algorithm.link_list = new_link_list
-
-
-            # TODO: find used links and remove them from algorithm.link_list
-            # TODO: compose disjoint path found
+                json_reply_service.append(path_endpoints)
+                algorithm.link_list = self.remove_traversed_links(algorithm.link_list, path_endpoints)
 
+        self.logger.info('self.json_reply = {:s}'.format(str(self.json_reply)))
 
-        self.logger.info('disjoint_paths = {:s}'.format(str(disjoint_paths)))
-        self.json_reply = {}
+    def get_reply(self) -> PathCompReply:
+        reply = PathCompReply()
+        for service_key,paths in self.json_reply.items():
+            grpc_service = self.add_service_to_reply(reply, service_key[0], service_key[1])
+            for path_endpoints in paths:
+                if path_endpoints is None: continue
+                grpc_connection = self.add_connection_to_reply(reply, grpc_service)
+                self.add_path_to_connection(grpc_connection, path_endpoints)
+        return reply
diff --git a/src/pathcomp/frontend/service/algorithms/_Algorithm.py b/src/pathcomp/frontend/service/algorithms/_Algorithm.py
index 1a8b57bd03acae8705a6db6c7f828ea010d1c96c..d4973f168dd7bce9fb830600c2d010fc238f3b48 100644
--- a/src/pathcomp/frontend/service/algorithms/_Algorithm.py
+++ b/src/pathcomp/frontend/service/algorithms/_Algorithm.py
@@ -14,7 +14,7 @@
 
 import json, logging, requests, uuid
 from typing import Dict, List, Optional, Tuple
-from common.proto.context_pb2 import Device, DeviceList, EndPointId, Link, LinkList, Service
+from common.proto.context_pb2 import Connection, Device, DeviceList, EndPointId, Link, LinkList, Service
 from common.proto.pathcomp_pb2 import PathCompReply, PathCompRequest
 from common.tools.grpc.Tools import grpc_message_to_json_string
 from pathcomp.frontend.Config import BACKEND_URL
@@ -32,13 +32,13 @@ class _Algorithm:
         self.algorithm_id = algorithm_id
         self.sync_paths = sync_paths
 
-        self.device_list : List[Device] = list()
+        self.device_list : List[Dict] = list()
         self.device_dict : Dict[str, Tuple[Dict, Device]] = dict()
         self.endpoint_dict : Dict[str, Dict[str, Tuple[Dict, EndPointId]]] = dict()
-        self.link_list : List[Link] = list()
+        self.link_list : List[Dict] = list()
         self.link_dict : Dict[str, Tuple[Dict, Link]] = dict()
         self.endpoint_to_link_dict : Dict[Tuple[str, str], Tuple[Dict, Link]] = dict()
-        self.service_list : List[Service] = list()
+        self.service_list : List[Dict] = list()
         self.service_dict : Dict[Tuple[str, str], Tuple[Dict, Service]] = dict()
 
     def add_devices(self, grpc_devices : DeviceList) -> None:
@@ -105,26 +105,40 @@ class _Algorithm:
         
         self.json_reply = reply.json()
 
+    def add_path_to_connection(self, connection : Connection, path_endpoints : List[Dict]) -> None:
+        for endpoint in path_endpoints:
+            device_uuid = endpoint['device_id']
+            endpoint_uuid = endpoint['endpoint_uuid']
+            endpoint_id = connection.path_hops_endpoint_ids.add()
+            endpoint_id.CopyFrom(self.endpoint_dict[device_uuid][endpoint_uuid][1])
+
+    def add_connection_to_reply(self, reply : PathCompReply, service : Service) -> Connection:
+        connection = reply.connections.add()
+        connection.connection_id.connection_uuid.uuid = str(uuid.uuid4())
+        connection.service_id.CopyFrom(service.service_id)
+        return connection
+
+    def add_service_to_reply(self, reply : PathCompReply, context_uuid : str, service_uuid : str) -> Service:
+        service_key = (context_uuid, service_uuid)
+        tuple_service = self.service_dict.get(service_key)
+        if tuple_service is None: raise Exception('ServiceKey({:s}) not found'.format(str(service_key)))
+        _, grpc_service = tuple_service
+
+        # TODO: implement support for multi-point services
+        service_endpoint_ids = grpc_service.service_endpoint_ids
+        if len(service_endpoint_ids) != 2: raise NotImplementedError('Service must have 2 endpoints')
+
+        service = reply.services.add()
+        service.CopyFrom(grpc_service)
+
+        return grpc_service
+
     def get_reply(self) -> PathCompReply:
         response_list = self.json_reply.get('response-list', [])
         reply = PathCompReply()
         for response in response_list:
             service_id = response['serviceId']
-            service_key = (service_id['contextId'], service_id['service_uuid'])
-            tuple_service = self.service_dict.get(service_key)
-            if tuple_service is None: raise Exception('ServiceKey({:s}) not found'.format(str(service_key)))
-            json_service, grpc_service = tuple_service
-
-            # TODO: implement support for multi-point services
-            service_endpoint_ids = grpc_service.service_endpoint_ids
-            if len(service_endpoint_ids) != 2: raise NotImplementedError('Service must have 2 endpoints')
-
-            service = reply.services.add()
-            service.CopyFrom(grpc_service)
-
-            connection = reply.connections.add()
-            connection.connection_id.connection_uuid.uuid = str(uuid.uuid4())
-            connection.service_id.CopyFrom(service.service_id)
+            grpc_service = self.add_service_to_reply(reply, service_id['contextId'], service_id['service_uuid'])
 
             no_path_issue = response.get('noPath', {}).get('issue')
             if no_path_issue is not None:
@@ -132,9 +146,10 @@ class _Algorithm:
                 # no_path_issue == 1 => no path due to a constraint
                 continue
 
-            service_paths = response['path']
+            for service_path in response['path']:
+                grpc_connection = self.add_connection_to_reply(reply, grpc_service)
+                self.add_path_to_connection(grpc_connection, service_path['devices'])
 
-            for service_path in service_paths:
                 # ... "path-capacity": {"total-size": {"value": 200, "unit": 0}},
                 # ... "path-latency": {"fixed-latency-characteristic": "10.000000"},
                 # ... "path-cost": {"cost-name": "", "cost-value": "5.000000", "cost-algorithm": "0.000000"},
@@ -147,10 +162,4 @@ class _Algorithm:
                 #path_cost_value = path_cost['cost-value']
                 #path_cost_algorithm = path_cost['cost-algorithm']
 
-                path_endpoints = service_path['devices']
-                for endpoint in path_endpoints:
-                    device_uuid = endpoint['device_id']
-                    endpoint_uuid = endpoint['endpoint_uuid']
-                    endpoint_id = connection.path_hops_endpoint_ids.add()
-                    endpoint_id.CopyFrom(self.endpoint_dict[device_uuid][endpoint_uuid][1])
         return reply
diff --git a/src/pathcomp/misc/example-results-kdisjointpaths.json b/src/pathcomp/misc/example-results-kdisjointpaths.json
new file mode 100644
index 0000000000000000000000000000000000000000..9eda25d484e45db53471ea3f655d511cbcc42c18
--- /dev/null
+++ b/src/pathcomp/misc/example-results-kdisjointpaths.json
@@ -0,0 +1,73 @@
+{
+    "connections": [
+        {
+            "connection_id": {"connection_uuid": {"uuid": "d8cb463a-77c4-4149-80fc-32c4842a191d"}},
+            "path_hops_endpoint_ids": [
+                {"device_id": {"device_uuid": {"uuid": "DC1-GW"}}, "endpoint_uuid": {"uuid": "int"},
+                    "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "DC1"}}},
+                {"device_id": {"device_uuid": {"uuid": "DC1-GW"}}, "endpoint_uuid": {"uuid": "eth1"},
+                    "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "DC1"}}},
+                {"device_id": {"device_uuid": {"uuid": "CS1-GW1"}}, "endpoint_uuid": {"uuid": "200"},
+                    "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "CS1"}}},
+                {"device_id": {"device_uuid": {"uuid": "TN-R2"}}, "endpoint_uuid": {"uuid": "1"},
+                    "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "TN"}}},
+                {"device_id": {"device_uuid": {"uuid": "TN-R3"}}, "endpoint_uuid": {"uuid": "100"},
+                    "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "TN"}}},
+                {"device_id": {"device_uuid": {"uuid": "CS2-GW1"}}, "endpoint_uuid": {"uuid": "1000"},
+                    "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "CS2"}}},
+                {"device_id": {"device_uuid": {"uuid": "DC2-GW"}}, "endpoint_uuid": {"uuid": "int"},
+                    "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "DC2"}}}
+            ],
+            "service_id": {
+                "context_id": {"context_uuid": {"uuid": "admin"}},
+                "service_uuid": {"uuid": "svc:DC1-GW/int==DC2-GW/int"}
+            },
+            "sub_service_ids": []
+        },
+        {
+            "connection_id": {"connection_uuid": {"uuid": "9f7c5075-0736-4d2a-8435-b8e8c37fa6ea"}},
+            "path_hops_endpoint_ids": [
+                {"device_id": {"device_uuid": {"uuid": "DC1-GW"}}, "endpoint_uuid": {"uuid": "int"},
+                    "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "DC1"}}},
+                {"device_id": {"device_uuid": {"uuid": "DC1-GW"}}, "endpoint_uuid": {"uuid": "eth2"},
+                    "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "DC1"}}},
+                {"device_id": {"device_uuid": {"uuid": "CS1-GW2"}}, "endpoint_uuid": {"uuid": "200"},
+                    "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "CS1"}}},
+                {"device_id": {"device_uuid": {"uuid": "TN-R1"}}, "endpoint_uuid": {"uuid": "3"},
+                    "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "TN"}}},
+                {"device_id": {"device_uuid": {"uuid": "TN-R3"}}, "endpoint_uuid": {"uuid": "200"},
+                    "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "TN"}}},
+                {"device_id": {"device_uuid": {"uuid": "CS2-GW2"}}, "endpoint_uuid": {"uuid": "1000"},
+                    "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "CS2"}}},
+                {"device_id": {"device_uuid": {"uuid": "DC2-GW"}}, "endpoint_uuid": {"uuid": "int"},
+                    "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "DC2"}}}
+            ],
+            "service_id": {
+                "context_id": {"context_uuid": {"uuid": "admin"}},
+                "service_uuid": {"uuid": "svc:DC1-GW/int==DC2-GW/int"}
+            },
+            "sub_service_ids": []
+        }
+    ],
+    "services": [
+        {
+            "service_id": {
+                "context_id": {"context_uuid": {"uuid": "admin"}},
+                "service_uuid": {"uuid": "svc:DC1-GW/int==DC2-GW/int"}
+            },
+            "service_type": "SERVICETYPE_L3NM",
+            "service_endpoint_ids": [
+                {"device_id": {"device_uuid": {"uuid": "DC1-GW"}}, "endpoint_uuid": {"uuid": "int"},
+                    "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "DC1"}}},
+                {"device_id": {"device_uuid": {"uuid": "DC2-GW"}}, "endpoint_uuid": {"uuid": "int"},
+                    "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "DC2"}}}
+            ],
+            "service_status": {"service_status": "SERVICESTATUS_PLANNED"},
+            "service_constraints": [
+                {"custom": {"constraint_type": "bandwidth[gbps]", "constraint_value": "10.0"}},
+                {"custom": {"constraint_type": "latency[ms]", "constraint_value": "12.0"}}
+            ],
+            "service_config": {"config_rules": []}
+        }
+    ]
+}
\ No newline at end of file
diff --git a/src/pathcomp/test-commands.sh b/src/pathcomp/misc/test-commands.sh
similarity index 96%
rename from src/pathcomp/test-commands.sh
rename to src/pathcomp/misc/test-commands.sh
index cb764fae11bf1326edce75e24cc9229c0f480379..17cf092e8cff5506d56784af092aaab8da7fec94 100644
--- a/src/pathcomp/test-commands.sh
+++ b/src/pathcomp/misc/test-commands.sh
@@ -29,3 +29,5 @@ docker network rm teraflowbridge
 docker images --filter="dangling=true" --quiet | xargs -r docker rmi
 
 docker exec -i pathcomp bash -c "pytest --log-level=INFO --verbose pathcomp/tests/test_unitary.py"
+
+./scripts/run_tests_locally-pathcomp-frontend.sh