diff --git a/northbound/client/sbi.go b/northbound/client/sbi.go
new file mode 100644
index 0000000000000000000000000000000000000000..526bbb8f9839dda2116628e116f1cfac9bdf73be
--- /dev/null
+++ b/northbound/client/sbi.go
@@ -0,0 +1,17 @@
+package client
+
+import (
+	spb "code.fbi.h-da.de/danet/api/go/gosdn/southbound"
+	"google.golang.org/grpc"
+)
+
+// SbiClient returns a client for the gRPC SBI service. It takes
+// the address of the gRPC endpoint and optional grpc.DialOption
+// as argument
+func SbiClient(addr string, opts ...grpc.DialOption) (spb.SbiServiceClient, error) {
+	conn, err := grpc.Dial(addr, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return spb.NewSbiServiceClient(conn), nil
+}
diff --git a/northbound/server/sbi.go b/northbound/server/sbi.go
new file mode 100644
index 0000000000000000000000000000000000000000..9a54c278c7e35335f0c21bd6f4152dce621b684c
--- /dev/null
+++ b/northbound/server/sbi.go
@@ -0,0 +1,49 @@
+package server
+
+import (
+	spb "code.fbi.h-da.de/danet/api/go/gosdn/southbound"
+	"code.fbi.h-da.de/danet/gosdn/metrics"
+	"code.fbi.h-da.de/danet/gosdn/store"
+	"github.com/google/uuid"
+	"github.com/prometheus/client_golang/prometheus"
+)
+
+type sbiServer struct {
+	spb.UnimplementedSbiServiceServer
+}
+
+func (s sbiServer) GetSchema(request *spb.GetSchemaRequest, stream spb.SbiService_GetSchemaServer) error {
+	labels := prometheus.Labels{"service": "pnd", "rpc": "get schema"}
+	start := metrics.StartHook(labels, grpcRequestsTotal)
+	defer metrics.FinishHook(labels, start, grpcRequestDurationSecondsTotal, grpcRequestDurationSeconds)
+
+	pid, err := uuid.Parse(request.Pid)
+	if err != nil {
+		return handleRPCError(labels, err)
+	}
+
+	sid, err := uuid.Parse(request.Sid)
+	if err != nil {
+		return handleRPCError(labels, err)
+	}
+
+	pnd, err := pndc.GetPND(pid)
+	if err != nil {
+		return handleRPCError(labels, err)
+	}
+
+	sbi, err := pnd.GetSBIs().(*store.SbiStore).GetSBI(sid)
+	if err != nil {
+		return handleRPCError(labels, err)
+	}
+
+	// TODO: only for testing; should be chunks of SchemaTree sent
+	payload := &spb.Payload{Chunk: sbi.SchemaTreeGzip()}
+
+	err = stream.Send(payload)
+	if err != nil {
+		return handleRPCError(labels, err)
+	}
+
+	return nil
+}