diff --git a/CMakeLists.txt b/CMakeLists.txt
index da6a244a88b3b072e6ecd48c839101ca44428b4e..b76f7ff3c95430547ded315d4245604646b51831 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -75,6 +75,7 @@ find_package(protobuf CONFIG REQUIRED)
 set(PROTO_FILES
     ${PROJECT_SOURCE_DIR}/proto/proto/caosdb/info/v1/main.proto
     ${PROJECT_SOURCE_DIR}/proto/proto/caosdb/entity/v1/main.proto
+    ${PROJECT_SOURCE_DIR}/proto/proto/caosdb/scripting/v1alpha1/main.proto
 )
 
 IF (BUILD_ACM)
diff --git a/include/CMakeLists.txt b/include/CMakeLists.txt
index 7a951bdacc7889b288004de4091eff638d561b7a..ff783db00f4dc4bc343495d8d542645f118f94f1 100644
--- a/include/CMakeLists.txt
+++ b/include/CMakeLists.txt
@@ -37,6 +37,7 @@ set(liblinkahead_INCL
     ${CMAKE_CURRENT_SOURCE_DIR}/linkahead/protobuf_helper.h
     ${CMAKE_CURRENT_SOURCE_DIR}/linkahead/result_table.h
     ${CMAKE_CURRENT_SOURCE_DIR}/linkahead/result_set.h
+    ${CMAKE_CURRENT_SOURCE_DIR}/linkahead/scripting.h
     ${CMAKE_CURRENT_SOURCE_DIR}/linkahead/status_code.h
     ${CMAKE_CURRENT_SOURCE_DIR}/linkahead/transaction.h
     ${CMAKE_CURRENT_SOURCE_DIR}/linkahead/transaction_handler.h
diff --git a/include/linkahead/scripting.h b/include/linkahead/scripting.h
new file mode 100644
index 0000000000000000000000000000000000000000..ad22591d3056c47110f1837b871c695f6c03bb67
--- /dev/null
+++ b/include/linkahead/scripting.h
@@ -0,0 +1,41 @@
+/*
+ * This file is a part of the LinkAhead Project.
+ * Copyright (C) 2025 Joscha Schmiedt <joscha@schmiedt.dev>
+ * Copyright (C) 2025 IndiScale GmbH <info@indiscale.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#include "caosdb/scripting/v1alpha1/main.pb.h"
+#include "caosdb/scripting/v1alpha1/main.grpc.pb.h"
+#include <string>
+#include <vector>
+
+#include <grpcpp/grpcpp.h>
+
+namespace linkahead::scripting {
+using namespace caosdb::scripting::v1alpha1;
+
+ExecuteServerSideScriptRequest construct_execute_server_side_script_request(
+  const std::string &script_name, const std::vector<std::string> &positional_arguments,
+  const std::vector<NamedArgument> &named_arguments, const std::vector<std::string> &script_files,
+  const std::string &auth_token, int timout_ms = 0, bool run_async = false);
+
+ExecuteServerSideScriptResponse
+call_server_side_script(const std::shared_ptr<grpc::Channel> &channel,
+                        const ExecuteServerSideScriptRequest &request);
+
+} // namespace linkahead::scripting
\ No newline at end of file
diff --git a/proto b/proto
index 6a46ce5d90237a09ac8ee28521ba01977e7f4400..f31b6002b89b5e36307508fc48bfd6078f66c7b2 160000
--- a/proto
+++ b/proto
@@ -1 +1 @@
-Subproject commit 6a46ce5d90237a09ac8ee28521ba01977e7f4400
+Subproject commit f31b6002b89b5e36307508fc48bfd6078f66c7b2
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index cdc2fa4189fdc11fbcb4565893ccf441153ed71a..db1f1eef58e8c84b01efe42a5c9081425859ac0f 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -30,6 +30,7 @@ set(liblinkahead_SRC
     ${CMAKE_CURRENT_SOURCE_DIR}/linkahead/result_set.cpp
     ${CMAKE_CURRENT_SOURCE_DIR}/linkahead/result_table.cpp
     ${CMAKE_CURRENT_SOURCE_DIR}/linkahead/result_table_impl.h
+    ${CMAKE_CURRENT_SOURCE_DIR}/linkahead/scripting.cpp
     ${CMAKE_CURRENT_SOURCE_DIR}/linkahead/transaction.cpp
     ${CMAKE_CURRENT_SOURCE_DIR}/linkahead/transaction_handler.cpp
     ${CMAKE_CURRENT_SOURCE_DIR}/linkahead/utility.cpp
diff --git a/src/linkahead/scripting.cpp b/src/linkahead/scripting.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..086ad9e06c096a51f0a1b24efb6b3076508e8c1a
--- /dev/null
+++ b/src/linkahead/scripting.cpp
@@ -0,0 +1,75 @@
+/*
+ * This file is a part of the LinkAhead Project.
+ * Copyright (C) 2025 Joscha Schmiedt <joscha@schmiedt.dev>
+ * Copyright (C) 2025 IndiScale GmbH <info@indiscale.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "linkahead/scripting.h"
+#include "caosdb/scripting/v1alpha1/main.pb.h"
+#include "caosdb/scripting/v1alpha1/main.grpc.pb.h"
+#include <string>
+#include <vector>
+
+using caosdb::scripting::v1alpha1::ExecuteServerSideScriptRequest;
+using caosdb::scripting::v1alpha1::ExecuteServerSideScriptResponse;
+using caosdb::scripting::v1alpha1::ServerSideScriptExecutionResult;
+using caosdb::scripting::v1alpha1::ServerSideScriptingService;
+// using namespace linkahead::scripting;
+
+ExecuteServerSideScriptRequest linkahead::scripting::construct_execute_server_side_script_request(
+  const std::string &script_name, const std::vector<std::string> &positional_arguments,
+  const std::vector<NamedArgument> &named_arguments, const std::vector<std::string> &script_files,
+  const std::string &auth_token, int timout_ms, bool run_async) {
+
+  // TODO(schmiedt): validate input parameters
+
+  // Use builder pattern to construct the request
+  ExecuteServerSideScriptRequest request;
+  request.set_script_filename(script_name);
+  request.set_timeout_ms(timout_ms);
+  request.set_run_async(run_async);
+  request.set_auth_token(auth_token);
+
+  for (const auto &arg : positional_arguments) {
+    request.add_positional_arguments(arg);
+  }
+  for (const auto &arg : named_arguments) {
+    *request.add_named_arguments() = arg;
+  }
+  for (const auto &file : script_files) {
+    request.add_script_files(file);
+  }
+  return request;
+}
+
+ExecuteServerSideScriptResponse
+linkahead::scripting::call_server_side_script(const std::shared_ptr<grpc::Channel> &channel,
+                                              const ExecuteServerSideScriptRequest &request) {
+  auto stub = ServerSideScriptingService::NewStub(channel);
+  grpc::ClientContext context;
+  ExecuteServerSideScriptResponse response;
+
+  grpc::Status status = stub->ExecuteServerSideScript(&context, request, &response);
+
+  // TODO(schmiedt): Handle status codes and errors. For now, we just throw an exception if the
+  // status is not OK
+  if (!status.ok()) {
+    throw std::runtime_error("RPC failed: " + status.error_message());
+  }
+
+  return response;
+}
\ No newline at end of file
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 7b70f9f14fcb0594f166713bee5821a96ae2f029..af23de9ed47b162db040ac01b722d9420eee0c9e 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -29,6 +29,7 @@ set(test_cases
     test_issues
     test_list_properties
     test_protobuf
+    test_scripting
     test_transaction
     test_utility
     test_value
diff --git a/test/test_scripting.cpp b/test/test_scripting.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..2bcb9d8277284a18aedd15e8f1e269d275872ba3
--- /dev/null
+++ b/test/test_scripting.cpp
@@ -0,0 +1,23 @@
+#include <linkahead/scripting.h>
+
+#include <gtest/gtest.h>
+
+using namespace linkahead::scripting;
+
+TEST(test_scripting, test_construct_request) {
+  const std::string script_name = "test_script";
+  const std::vector<std::string> positional_arguments = {"arg1", "arg2"};
+  const std::vector<NamedArgument> named_arguments = {}; // TODO(schmiedt): fill with test data
+  const std::vector<std::string> script_files = {"file1", "file2"};
+  const std::string auth_token = "token";
+  int timeout_ms = 1000;
+  bool run_async = true;
+
+  auto request =
+    construct_execute_server_side_script_request(script_name, positional_arguments, named_arguments,
+                                                 script_files, auth_token, timeout_ms, run_async);
+
+  EXPECT_EQ(request.script_filename(), script_name);
+  EXPECT_EQ(request.timeout_ms(), timeout_ms);
+  EXPECT_EQ(request.run_async(), run_async);
+}
\ No newline at end of file