diff --git a/.gitmodules b/.gitmodules
index bec5f298a11200a81528f430e9df83913efb5827..222a8235d19134c1075d8499b214c9c45d841122 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -64,3 +64,6 @@
 [submodule "libdap-python"]
 	path = libdap-python
 	url = https://gitlab.demlabs.net/cellframe/libdap-python.git
+[submodule "libdap-client-python"]
+	path = libdap-client-python
+	url = https://gitlab.demlabs.net/cellframe/libdap-client-python.git
diff --git a/include/wrapping_dap_chain_net_node_client.h b/include/wrapping_dap_chain_net_node_client.h
new file mode 100644
index 0000000000000000000000000000000000000000..c940a7a4a9083d0814b5a80225642775a0d78efa
--- /dev/null
+++ b/include/wrapping_dap_chain_net_node_client.h
@@ -0,0 +1,85 @@
+#ifndef _WRAPPING_DAP_CHAIN_NODE_CLIENT_
+#define _WRAPPING_DAP_CHAIN_NODE_CLIENT_
+
+#include <Python.h>
+#include "dap_chain_node_client.h"
+#include "wrapping_dap_chain_net_node_info.h"
+#include "libdap_client_python.h"
+#include "wrapping_dap_client_stage.h"
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+typedef struct PyDapChainNodeClient{
+    PyObject_HEAD
+    dap_chain_node_client_t *node_client;
+}PyDapChainNodeClientObject;
+
+int dap_chain_node_client_init_py(void);
+void dap_chain_node_client_deinit_py(void);
+
+PyObject *dap_chain_client_connect_py(PyObject *self, PyObject *args);
+PyObject *dap_chain_node_client_connect_py(PyObject *self, PyObject *args);
+PyObject *dap_chain_node_client_close_py(PyObject *self, PyObject *args);
+PyObject *dap_chain_node_client_send_ch_pkt_py(PyObject *self, PyObject *args);
+PyObject *dap_chain_node_client_wait_py(PyObject *self, PyObject *args);
+PyObject *dap_chain_node_client_set_callbacks_py(PyObject *self, PyObject *args);
+
+static PyMethodDef DapChainNodeClientMethods[] = {
+    {"clientConnect", dap_chain_client_connect_py, METH_VARARGS | METH_STATIC, ""},
+    {"nodeClientConnect", (PyCFunction)dap_chain_node_client_connect_py, METH_VARARGS | METH_STATIC, ""},
+    {"close", (PyCFunction)dap_chain_node_client_close_py, METH_VARARGS, ""},
+    {"sendChPkt", (PyCFunction)dap_chain_node_client_send_ch_pkt_py, METH_VARARGS, ""},
+    {"wait", (PyCFunction)dap_chain_node_client_wait_py, METH_VARARGS, ""},
+    {"setCallbacks", (PyCFunction)dap_chain_node_client_set_callbacks_py, METH_VARARGS | METH_STATIC, ""},
+    {NULL, NULL, 0, NULL}
+};
+
+static PyTypeObject DapChainNodeClientObject_DapChainNodeClientObjectType = {
+    PyVarObject_HEAD_INIT(NULL, 0)
+    "CellFrame.Chain.Node.Client",            /* tp_name */
+    sizeof(PyDapChainNodeClientObject),     /* tp_basicsize */
+    0,                               /* tp_itemsize */
+    0,                               /* tp_dealloc */
+    0,                               /* tp_print */
+    0,                               /* tp_getattr */
+    0,                               /* tp_setattr */
+    0,                               /* tp_reserved */
+    0,                               /* tp_repr */
+    0,                               /* tp_as_number */
+    0,                               /* tp_as_sequence */
+    0,                               /* tp_as_mapping */
+    0,                               /* tp_hash  */
+    0,                               /* tp_call */
+    0,                               /* tp_str */
+    0,                               /* tp_getattro */
+    0,                               /* tp_setattro */
+    0,                               /* tp_as_buffer */
+    Py_TPFLAGS_DEFAULT |
+        Py_TPFLAGS_BASETYPE,         /* tp_flags */
+    "Chain net node client object",              /* tp_doc */
+    0,		                         /* tp_traverse */
+    0,		                         /* tp_clear */
+    0,		                         /* tp_richcompare */
+    0,                               /* tp_weaklistoffset */
+    0,		                         /* tp_iter */
+    0,		                         /* tp_iternext */
+    DapChainNodeClientMethods,              /* tp_methods */
+    0,                               /* tp_members */
+    0,                               /* tp_getset */
+    0,                               /* tp_base */
+    0,                               /* tp_dict */
+    0,                               /* tp_descr_get */
+    0,                               /* tp_descr_set */
+    0,                               /* tp_dictoffset */
+    0,                               /* tp_init */
+    0,                               /* tp_alloc */
+    PyType_GenericNew,       /* tp_new */
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //_WRAPPING_DAP_CHAIN_NODE_CLIENT_
diff --git a/libdap-client-python b/libdap-client-python
new file mode 160000
index 0000000000000000000000000000000000000000..b1918f7c8378d1e03e2915565c3764c4a803b2b6
--- /dev/null
+++ b/libdap-client-python
@@ -0,0 +1 @@
+Subproject commit b1918f7c8378d1e03e2915565c3764c4a803b2b6
diff --git a/src/wrapping_dap_chain_net_node_client.c b/src/wrapping_dap_chain_net_node_client.c
new file mode 100644
index 0000000000000000000000000000000000000000..4a2e5b08ed538a426b61e6362aee6f5f15971b17
--- /dev/null
+++ b/src/wrapping_dap_chain_net_node_client.c
@@ -0,0 +1,66 @@
+#include "wrapping_dap_chain_net_node_client.h"
+
+int dap_chain_node_client_init_py(void){
+    return dap_chain_node_client_init();
+}
+void dap_chain_node_client_deinit_py(void){
+    dap_chain_node_client_deinit();
+}
+
+PyObject *dap_chain_client_connect_py(PyObject *self, PyObject *args){
+    PyObject *obj_node_info;
+    PyObject *obj_client_stage;
+    const char *active_channels;
+    if (!PyArg_ParseTuple(args, "O|O|s", &obj_node_info, &obj_client_stage, &active_channels))
+        return NULL;
+    PyObject *obj_node_client = _PyObject_New(&DapChainNodeClientObject_DapChainNodeClientObjectType);
+    ((PyDapChainNodeClientObject*)obj_node_client)->node_client =dap_chain_client_connect(
+                ((PyDapChainNodeInfoObject*)obj_node_info)->node_info,
+                ((PyDapClientStageObject*)obj_client_stage)->stage, active_channels);
+    return Py_BuildValue("O", obj_node_client);
+}
+PyObject *dap_chain_node_client_connect_py(PyObject *self, PyObject *args){
+    if (self != NULL){
+        PyErr_SetString(PyExc_SyntaxWarning, "This is method called statically");
+        return NULL;
+    }
+    PyObject *obj_node_info;
+    if (!PyArg_ParseTuple(args, "O", &obj_node_info))
+        return NULL;
+    PyObject *obj_node_client = _PyObject_New(&DapChainNodeClientObject_DapChainNodeClientObjectType);
+    ((PyDapChainNodeClientObject*)obj_node_client)->node_client = dap_chain_node_client_connect(((PyDapChainNodeInfoObject*)obj_node_info)->node_info);
+    return Py_BuildValue("O", obj_node_client);
+}
+PyObject *dap_chain_node_client_close_py(PyObject *self, PyObject *args){
+    dap_chain_node_client_close(((PyDapChainNodeClientObject*)self)->node_client);
+    return PyLong_FromLong(0);
+}
+PyObject *dap_chain_node_client_send_ch_pkt_py(PyObject *self, PyObject *args){
+    uint8_t ch_id;
+    uint8_t type;
+    PyObject *obj_buf;
+    void *buf;
+    size_t buf_size;
+    if (!PyArg_ParseTuple(args, "b|b|O", &ch_id, &type, &obj_buf))
+        return NULL;
+    buf = PyBytes_AsString(obj_buf);
+    buf_size = (size_t)PyBytes_Size(buf);
+    int res = dap_chain_node_client_send_ch_pkt(((PyDapChainNodeClientObject*)self)->node_client, ch_id, type, buf, buf_size);
+    return PyLong_FromLong(res);
+}
+PyObject *dap_chain_node_client_wait_py(PyObject *self, PyObject *args){
+    int waited_state;
+    int timeout_ms;
+    if (!PyArg_ParseTuple(args, "i|i", &waited_state, &timeout_ms))
+        return NULL;
+    int res = dap_chain_node_client_wait(((PyDapChainNodeClientObject*)self)->node_client, waited_state, timeout_ms);
+    return PyLong_FromLong(res);
+}
+PyObject *dap_chain_node_client_set_callbacks_py(PyObject *self, PyObject *args){
+    PyObject *obj_dap_client;
+    uint8_t ch_id;
+    if (!PyArg_ParseTuple(args, "O|b", &obj_dap_client, &ch_id))
+        return NULL;
+    int res = dap_chain_node_client_set_callbacks(((PyDapClientObject*)obj_dap_client)->client, ch_id);
+    return PyLong_FromLong(res);
+}