diff --git a/CMakeLists.txt b/CMakeLists.txt
index 5261bea739d11c17e649470777565c17d5db8ae9..e9c31bc18ea026b89a95f7ad8f3517bebe18b877 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -192,6 +192,7 @@ add_library(beyond-protocol STATIC
 	src/protocol.cpp
 	src/rpc.cpp
     src/channelUtils.cpp
+    src/service.cpp
 )
 
 target_include_directories(beyond-protocol PUBLIC
diff --git a/include/ftl/protocol/self.hpp b/include/ftl/protocol/self.hpp
index d73bbd1f91ddd5be397a1e4da425f5c31c6ed694..ad3ba198f5f4b41d8206314c61527a4171c6bf0a 100644
--- a/include/ftl/protocol/self.hpp
+++ b/include/ftl/protocol/self.hpp
@@ -25,6 +25,7 @@ namespace protocol {
 
 class Node;
 class Stream;
+class Service;
 
 /**
  * @brief A wrapper providing RPC API and local node management. Internally the
@@ -48,6 +49,16 @@ class Self {
      */
     std::shared_ptr<ftl::protocol::Node> connectNode(const std::string &uri);
 
+    /**
+     * @brief Connect to the web service.
+     * 
+     * Only one service connection is allowed per self object.
+     * 
+     * @param uri 
+     * @return std::shared_ptr<ftl::protocol::Service> 
+     */
+    std::shared_ptr<ftl::protocol::Service> connectService(const std::string &uri);
+
     /**
      * @brief Create a new stream. Use the namespace method if possible.
      * 
diff --git a/include/ftl/protocol/service.hpp b/include/ftl/protocol/service.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..72cd4a946e8b972a97d8750edcd8961d6d096e9c
--- /dev/null
+++ b/include/ftl/protocol/service.hpp
@@ -0,0 +1,21 @@
+/**
+ * @file service.hpp
+ * @copyright Copyright (c) 2022 University of Turku, MIT License
+ * @author Nicolas Pope
+ */
+
+#pragma once
+
+#include <ftl/protocol/node.hpp>
+
+namespace ftl {
+namespace protocol {
+
+class Service: public ftl::protocol::Node {
+ public:
+    explicit Service(const ftl::net::PeerPtr &impl);
+    virtual ~Service();
+};
+
+}  // namespace protocol
+}  // namespace ftl
diff --git a/src/protocol.cpp b/src/protocol.cpp
index 012198d2cc9d66e177d33a0d7c48e7d8c6f6320a..32291fc22dac793c8dbd11b223990c642d853710 100644
--- a/src/protocol.cpp
+++ b/src/protocol.cpp
@@ -36,9 +36,9 @@ std::shared_ptr<ftl::protocol::Self> ftl::createDummySelf() {
     return std::make_shared<ftl::protocol::Self>(u);
 }
 
-/*std::shared_ptr<ftl::protocol::Service> ftl::setServiceProvider(const std::string &uri) {
-
-}*/
+std::shared_ptr<ftl::protocol::Service> ftl::setServiceProvider(const std::string &uri) {
+    return getSelf()->connectService(uri);
+}
 
 std::shared_ptr<ftl::protocol::Node> ftl::connectNode(const std::string &uri) {
     return getSelf()->connectNode(uri);
diff --git a/src/self.cpp b/src/self.cpp
index 627646b4ada755752a836a3bd263f66178691e8d..7331266f47551fef4cf639324cda99b95799879d 100644
--- a/src/self.cpp
+++ b/src/self.cpp
@@ -6,6 +6,7 @@
 
 #include "universe.hpp"
 #include <ftl/protocol/self.hpp>
+#include <ftl/protocol/service.hpp>
 #include "./streams/netstream.hpp"
 #include "./streams/filestream.hpp"
 #include <ftl/protocol/muxer.hpp>
@@ -24,6 +25,10 @@ std::shared_ptr<ftl::protocol::Node> Self::connectNode(const std::string &uri) {
     return std::make_shared<ftl::protocol::Node>(universe_->connect(uri));
 }
 
+std::shared_ptr<ftl::protocol::Service> Self::connectService(const std::string &uri) {
+    return std::make_shared<ftl::protocol::Service>(universe_->connect(uri));
+}
+
 std::shared_ptr<ftl::protocol::Stream> Self::createStream(const std::string &uri) {
     ftl::URI u(uri);
 
diff --git a/src/service.cpp b/src/service.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..1de41d427d744ed7f650433a8230156c1cacdd9a
--- /dev/null
+++ b/src/service.cpp
@@ -0,0 +1,14 @@
+/**
+ * @file service.cpp
+ * @copyright Copyright (c) 2022 University of Turku, MIT License
+ * @author Nicolas Pope
+ */
+
+#include <ftl/protocol/service.hpp>
+
+using ftl::protocol::Service;
+using ftl::protocol::Node;
+
+Service::Service(const ftl::net::PeerPtr &impl): Node(impl) {}
+
+Service::~Service() {}
diff --git a/test/rpc_integration.cpp b/test/rpc_integration.cpp
index 1ea1ad3b810663182e53f83db5683546e346bc29..e0c0b7e8072bd4bc76c88676fdaa32275c34b18b 100644
--- a/test/rpc_integration.cpp
+++ b/test/rpc_integration.cpp
@@ -2,6 +2,7 @@
 #include <ftl/protocol.hpp>
 #include <ftl/protocol/self.hpp>
 #include <ftl/protocol/node.hpp>
+#include <ftl/protocol/service.hpp>
 #include <ftl/uri.hpp>
 #include <ftl/exception.hpp>
 #include <ftl/lib/nlohmann/json.hpp>
@@ -50,7 +51,7 @@ TEST_CASE("RPC List Streams", "[rpc]") {
     {
         auto uri = "tcp://127.0.0.1:" + std::to_string(self->getListeningURIs().front().getPort());
         LOG(INFO) << uri;
-        auto p = ftl::connectNode(uri);
+        auto p = ftl::setServiceProvider(uri);
         REQUIRE(p);
         REQUIRE(p->waitConnection(5));
         REQUIRE(self->waitConnections(5) == 1);