Author: Jonas Devlieghere
Date: 2025-08-07T09:01:28-07:00
New Revision: 44aedacb1b64b415fddfada39eb876602980ea72

URL: 
https://github.com/llvm/llvm-project/commit/44aedacb1b64b415fddfada39eb876602980ea72
DIFF: 
https://github.com/llvm/llvm-project/commit/44aedacb1b64b415fddfada39eb876602980ea72.diff

LOG: [lldb] Move the generic MCP server code into Protocol/MCP (NFC) (#152396)

This is a continuation of #152188, which started splitting up the MCP
implementation into a generic implementation in Protocol/MCP that will
be shared between LLDB and lldb-mcp.

For now I kept all the networking code in the MCP server plugin. Once
the changes to JSONTransport land, we might be able to move more of it
into the Protocol library.

Added: 
    lldb/include/lldb/Protocol/MCP/Server.h
    lldb/source/Protocol/MCP/Server.cpp

Modified: 
    lldb/include/lldb/Protocol/MCP/Protocol.h
    lldb/source/Plugins/Protocol/MCP/ProtocolServerMCP.cpp
    lldb/source/Plugins/Protocol/MCP/ProtocolServerMCP.h
    lldb/source/Protocol/MCP/CMakeLists.txt

Removed: 
    


################################################################################
diff  --git a/lldb/include/lldb/Protocol/MCP/Protocol.h 
b/lldb/include/lldb/Protocol/MCP/Protocol.h
index c43b06809bd3f..6448416eee08f 100644
--- a/lldb/include/lldb/Protocol/MCP/Protocol.h
+++ b/lldb/include/lldb/Protocol/MCP/Protocol.h
@@ -21,7 +21,7 @@
 
 namespace lldb_protocol::mcp {
 
-static llvm::StringLiteral kVersion = "2024-11-05";
+static llvm::StringLiteral kProtocolVersion = "2024-11-05";
 
 /// A request that expects a response.
 struct Request {

diff  --git a/lldb/include/lldb/Protocol/MCP/Server.h 
b/lldb/include/lldb/Protocol/MCP/Server.h
new file mode 100644
index 0000000000000..2ac05880de86b
--- /dev/null
+++ b/lldb/include/lldb/Protocol/MCP/Server.h
@@ -0,0 +1,70 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_PROTOCOL_MCP_SERVER_H
+#define LLDB_PROTOCOL_MCP_SERVER_H
+
+#include "lldb/Protocol/MCP/Protocol.h"
+#include "lldb/Protocol/MCP/Resource.h"
+#include "lldb/Protocol/MCP/Tool.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/Support/Error.h"
+#include <mutex>
+
+namespace lldb_protocol::mcp {
+
+class Server {
+public:
+  Server(std::string name, std::string version);
+  virtual ~Server() = default;
+
+  void AddTool(std::unique_ptr<Tool> tool);
+  void AddResourceProvider(std::unique_ptr<ResourceProvider> 
resource_provider);
+
+protected:
+  virtual Capabilities GetCapabilities() = 0;
+
+  using RequestHandler =
+      std::function<llvm::Expected<Response>(const Request &)>;
+  using NotificationHandler = std::function<void(const Notification &)>;
+
+  void AddRequestHandlers();
+
+  void AddRequestHandler(llvm::StringRef method, RequestHandler handler);
+  void AddNotificationHandler(llvm::StringRef method,
+                              NotificationHandler handler);
+
+  llvm::Expected<std::optional<Message>> HandleData(llvm::StringRef data);
+
+  llvm::Expected<Response> Handle(Request request);
+  void Handle(Notification notification);
+
+  llvm::Expected<Response> InitializeHandler(const Request &);
+
+  llvm::Expected<Response> ToolsListHandler(const Request &);
+  llvm::Expected<Response> ToolsCallHandler(const Request &);
+
+  llvm::Expected<Response> ResourcesListHandler(const Request &);
+  llvm::Expected<Response> ResourcesReadHandler(const Request &);
+
+  std::mutex m_mutex;
+
+private:
+  const std::string m_name;
+  const std::string m_version;
+
+  llvm::StringMap<std::unique_ptr<Tool>> m_tools;
+  std::vector<std::unique_ptr<ResourceProvider>> m_resource_providers;
+
+  llvm::StringMap<RequestHandler> m_request_handlers;
+  llvm::StringMap<NotificationHandler> m_notification_handlers;
+};
+
+} // namespace lldb_protocol::mcp
+
+#endif

diff  --git a/lldb/source/Plugins/Protocol/MCP/ProtocolServerMCP.cpp 
b/lldb/source/Plugins/Protocol/MCP/ProtocolServerMCP.cpp
index c9fe474d45c49..c359663239dcc 100644
--- a/lldb/source/Plugins/Protocol/MCP/ProtocolServerMCP.cpp
+++ b/lldb/source/Plugins/Protocol/MCP/ProtocolServerMCP.cpp
@@ -27,25 +27,12 @@ using namespace llvm;
 LLDB_PLUGIN_DEFINE(ProtocolServerMCP)
 
 static constexpr size_t kChunkSize = 1024;
+static constexpr llvm::StringLiteral kName = "lldb-mcp";
+static constexpr llvm::StringLiteral kVersion = "0.1.0";
 
-ProtocolServerMCP::ProtocolServerMCP() : ProtocolServer() {
-  AddRequestHandler("initialize",
-                    std::bind(&ProtocolServerMCP::InitializeHandler, this,
-                              std::placeholders::_1));
-
-  AddRequestHandler("tools/list",
-                    std::bind(&ProtocolServerMCP::ToolsListHandler, this,
-                              std::placeholders::_1));
-  AddRequestHandler("tools/call",
-                    std::bind(&ProtocolServerMCP::ToolsCallHandler, this,
-                              std::placeholders::_1));
-
-  AddRequestHandler("resources/list",
-                    std::bind(&ProtocolServerMCP::ResourcesListHandler, this,
-                              std::placeholders::_1));
-  AddRequestHandler("resources/read",
-                    std::bind(&ProtocolServerMCP::ResourcesReadHandler, this,
-                              std::placeholders::_1));
+ProtocolServerMCP::ProtocolServerMCP()
+    : ProtocolServer(),
+      lldb_protocol::mcp::Server(std::string(kName), std::string(kVersion)) {
   AddNotificationHandler("notifications/initialized",
                          [](const lldb_protocol::mcp::Notification &) {
                            LLDB_LOG(GetLog(LLDBLog::Host),
@@ -77,32 +64,6 @@ llvm::StringRef 
ProtocolServerMCP::GetPluginDescriptionStatic() {
   return "MCP Server.";
 }
 
-llvm::Expected<lldb_protocol::mcp::Response>
-ProtocolServerMCP::Handle(lldb_protocol::mcp::Request request) {
-  auto it = m_request_handlers.find(request.method);
-  if (it != m_request_handlers.end()) {
-    llvm::Expected<lldb_protocol::mcp::Response> response = 
it->second(request);
-    if (!response)
-      return response;
-    response->id = request.id;
-    return *response;
-  }
-
-  return make_error<MCPError>(
-      llvm::formatv("no handler for request: {0}", request.method).str());
-}
-
-void ProtocolServerMCP::Handle(lldb_protocol::mcp::Notification notification) {
-  auto it = m_notification_handlers.find(notification.method);
-  if (it != m_notification_handlers.end()) {
-    it->second(notification);
-    return;
-  }
-
-  LLDB_LOG(GetLog(LLDBLog::Host), "MPC notification: {0} ({1})",
-           notification.method, notification.params);
-}
-
 void ProtocolServerMCP::AcceptCallback(std::unique_ptr<Socket> socket) {
   LLDB_LOG(GetLog(LLDBLog::Host), "New MCP client ({0}) connected",
            m_clients.size() + 1);
@@ -157,7 +118,7 @@ llvm::Error ProtocolServerMCP::ReadCallback(Client &client) 
{
 }
 
 llvm::Error ProtocolServerMCP::Start(ProtocolServer::Connection connection) {
-  std::lock_guard<std::mutex> guard(m_server_mutex);
+  std::lock_guard<std::mutex> guard(m_mutex);
 
   if (m_running)
     return llvm::createStringError("the MCP server is already running");
@@ -189,7 +150,7 @@ llvm::Error 
ProtocolServerMCP::Start(ProtocolServer::Connection connection) {
 
 llvm::Error ProtocolServerMCP::Stop() {
   {
-    std::lock_guard<std::mutex> guard(m_server_mutex);
+    std::lock_guard<std::mutex> guard(m_mutex);
     if (!m_running)
       return createStringError("the MCP sever is not running");
     m_running = false;
@@ -204,7 +165,7 @@ llvm::Error ProtocolServerMCP::Stop() {
     m_loop_thread.join();
 
   {
-    std::lock_guard<std::mutex> guard(m_server_mutex);
+    std::lock_guard<std::mutex> guard(m_mutex);
     m_listener.reset();
     m_listen_handlers.clear();
     m_clients.clear();
@@ -213,48 +174,6 @@ llvm::Error ProtocolServerMCP::Stop() {
   return llvm::Error::success();
 }
 
-llvm::Expected<std::optional<lldb_protocol::mcp::Message>>
-ProtocolServerMCP::HandleData(llvm::StringRef data) {
-  auto message = llvm::json::parse<lldb_protocol::mcp::Message>(/*JSON=*/data);
-  if (!message)
-    return message.takeError();
-
-  if (const lldb_protocol::mcp::Request *request =
-          std::get_if<lldb_protocol::mcp::Request>(&(*message))) {
-    llvm::Expected<lldb_protocol::mcp::Response> response = Handle(*request);
-
-    // Handle failures by converting them into an Error message.
-    if (!response) {
-      lldb_protocol::mcp::Error protocol_error;
-      llvm::handleAllErrors(
-          response.takeError(),
-          [&](const MCPError &err) { protocol_error = err.toProtcolError(); },
-          [&](const llvm::ErrorInfoBase &err) {
-            protocol_error.error.code = MCPError::kInternalError;
-            protocol_error.error.message = err.message();
-          });
-      protocol_error.id = request->id;
-      return protocol_error;
-    }
-
-    return *response;
-  }
-
-  if (const lldb_protocol::mcp::Notification *notification =
-          std::get_if<lldb_protocol::mcp::Notification>(&(*message))) {
-    Handle(*notification);
-    return std::nullopt;
-  }
-
-  if (std::get_if<lldb_protocol::mcp::Error>(&(*message)))
-    return llvm::createStringError("unexpected MCP message: error");
-
-  if (std::get_if<lldb_protocol::mcp::Response>(&(*message)))
-    return llvm::createStringError("unexpected MCP message: response");
-
-  llvm_unreachable("all message types handled");
-}
-
 lldb_protocol::mcp::Capabilities ProtocolServerMCP::GetCapabilities() {
   lldb_protocol::mcp::Capabilities capabilities;
   capabilities.tools.listChanged = true;
@@ -263,158 +182,3 @@ lldb_protocol::mcp::Capabilities 
ProtocolServerMCP::GetCapabilities() {
   capabilities.resources.listChanged = false;
   return capabilities;
 }
-
-void ProtocolServerMCP::AddTool(std::unique_ptr<Tool> tool) {
-  std::lock_guard<std::mutex> guard(m_server_mutex);
-
-  if (!tool)
-    return;
-  m_tools[tool->GetName()] = std::move(tool);
-}
-
-void ProtocolServerMCP::AddResourceProvider(
-    std::unique_ptr<ResourceProvider> resource_provider) {
-  std::lock_guard<std::mutex> guard(m_server_mutex);
-
-  if (!resource_provider)
-    return;
-  m_resource_providers.push_back(std::move(resource_provider));
-}
-
-void ProtocolServerMCP::AddRequestHandler(llvm::StringRef method,
-                                          RequestHandler handler) {
-  std::lock_guard<std::mutex> guard(m_server_mutex);
-  m_request_handlers[method] = std::move(handler);
-}
-
-void ProtocolServerMCP::AddNotificationHandler(llvm::StringRef method,
-                                               NotificationHandler handler) {
-  std::lock_guard<std::mutex> guard(m_server_mutex);
-  m_notification_handlers[method] = std::move(handler);
-}
-
-llvm::Expected<lldb_protocol::mcp::Response>
-ProtocolServerMCP::InitializeHandler(
-    const lldb_protocol::mcp::Request &request) {
-  lldb_protocol::mcp::Response response;
-  response.result.emplace(llvm::json::Object{
-      {"protocolVersion", lldb_protocol::mcp::kVersion},
-      {"capabilities", GetCapabilities()},
-      {"serverInfo",
-       llvm::json::Object{{"name", kName}, {"version", kVersion}}}});
-  return response;
-}
-
-llvm::Expected<lldb_protocol::mcp::Response>
-ProtocolServerMCP::ToolsListHandler(
-    const lldb_protocol::mcp::Request &request) {
-  lldb_protocol::mcp::Response response;
-
-  llvm::json::Array tools;
-  for (const auto &tool : m_tools)
-    tools.emplace_back(toJSON(tool.second->GetDefinition()));
-
-  response.result.emplace(llvm::json::Object{{"tools", std::move(tools)}});
-
-  return response;
-}
-
-llvm::Expected<lldb_protocol::mcp::Response>
-ProtocolServerMCP::ToolsCallHandler(
-    const lldb_protocol::mcp::Request &request) {
-  lldb_protocol::mcp::Response response;
-
-  if (!request.params)
-    return llvm::createStringError("no tool parameters");
-
-  const json::Object *param_obj = request.params->getAsObject();
-  if (!param_obj)
-    return llvm::createStringError("no tool parameters");
-
-  const json::Value *name = param_obj->get("name");
-  if (!name)
-    return llvm::createStringError("no tool name");
-
-  llvm::StringRef tool_name = name->getAsString().value_or("");
-  if (tool_name.empty())
-    return llvm::createStringError("no tool name");
-
-  auto it = m_tools.find(tool_name);
-  if (it == m_tools.end())
-    return llvm::createStringError(llvm::formatv("no tool \"{0}\"", 
tool_name));
-
-  lldb_protocol::mcp::ToolArguments tool_args;
-  if (const json::Value *args = param_obj->get("arguments"))
-    tool_args = *args;
-
-  llvm::Expected<lldb_protocol::mcp::TextResult> text_result =
-      it->second->Call(tool_args);
-  if (!text_result)
-    return text_result.takeError();
-
-  response.result.emplace(toJSON(*text_result));
-
-  return response;
-}
-
-llvm::Expected<lldb_protocol::mcp::Response>
-ProtocolServerMCP::ResourcesListHandler(
-    const lldb_protocol::mcp::Request &request) {
-  lldb_protocol::mcp::Response response;
-
-  llvm::json::Array resources;
-
-  std::lock_guard<std::mutex> guard(m_server_mutex);
-  for (std::unique_ptr<ResourceProvider> &resource_provider_up :
-       m_resource_providers) {
-    for (const lldb_protocol::mcp::Resource &resource :
-         resource_provider_up->GetResources())
-      resources.push_back(resource);
-  }
-  response.result.emplace(
-      llvm::json::Object{{"resources", std::move(resources)}});
-
-  return response;
-}
-
-llvm::Expected<lldb_protocol::mcp::Response>
-ProtocolServerMCP::ResourcesReadHandler(
-    const lldb_protocol::mcp::Request &request) {
-  lldb_protocol::mcp::Response response;
-
-  if (!request.params)
-    return llvm::createStringError("no resource parameters");
-
-  const json::Object *param_obj = request.params->getAsObject();
-  if (!param_obj)
-    return llvm::createStringError("no resource parameters");
-
-  const json::Value *uri = param_obj->get("uri");
-  if (!uri)
-    return llvm::createStringError("no resource uri");
-
-  llvm::StringRef uri_str = uri->getAsString().value_or("");
-  if (uri_str.empty())
-    return llvm::createStringError("no resource uri");
-
-  std::lock_guard<std::mutex> guard(m_server_mutex);
-  for (std::unique_ptr<ResourceProvider> &resource_provider_up :
-       m_resource_providers) {
-    llvm::Expected<lldb_protocol::mcp::ResourceResult> result =
-        resource_provider_up->ReadResource(uri_str);
-    if (result.errorIsA<UnsupportedURI>()) {
-      llvm::consumeError(result.takeError());
-      continue;
-    }
-    if (!result)
-      return result.takeError();
-
-    lldb_protocol::mcp::Response response;
-    response.result.emplace(std::move(*result));
-    return response;
-  }
-
-  return make_error<MCPError>(
-      llvm::formatv("no resource handler for uri: {0}", uri_str).str(),
-      MCPError::kResourceNotFound);
-}

diff  --git a/lldb/source/Plugins/Protocol/MCP/ProtocolServerMCP.h 
b/lldb/source/Plugins/Protocol/MCP/ProtocolServerMCP.h
index 2ea9585a2334b..7fe909a728b85 100644
--- a/lldb/source/Plugins/Protocol/MCP/ProtocolServerMCP.h
+++ b/lldb/source/Plugins/Protocol/MCP/ProtocolServerMCP.h
@@ -13,14 +13,13 @@
 #include "lldb/Host/MainLoop.h"
 #include "lldb/Host/Socket.h"
 #include "lldb/Protocol/MCP/Protocol.h"
-#include "lldb/Protocol/MCP/Resource.h"
-#include "lldb/Protocol/MCP/Tool.h"
-#include "llvm/ADT/StringMap.h"
+#include "lldb/Protocol/MCP/Server.h"
 #include <thread>
 
 namespace lldb_private::mcp {
 
-class ProtocolServerMCP : public ProtocolServer {
+class ProtocolServerMCP : public ProtocolServer,
+                          public lldb_protocol::mcp::Server {
 public:
   ProtocolServerMCP();
   virtual ~ProtocolServerMCP() override;
@@ -40,48 +39,10 @@ class ProtocolServerMCP : public ProtocolServer {
 
   Socket *GetSocket() const override { return m_listener.get(); }
 
-protected:
-  using RequestHandler =
-      std::function<llvm::Expected<lldb_protocol::mcp::Response>(
-          const lldb_protocol::mcp::Request &)>;
-  using NotificationHandler =
-      std::function<void(const lldb_protocol::mcp::Notification &)>;
-
-  void AddTool(std::unique_ptr<lldb_protocol::mcp::Tool> tool);
-  void AddResourceProvider(
-      std::unique_ptr<lldb_protocol::mcp::ResourceProvider> resource_provider);
-
-  void AddRequestHandler(llvm::StringRef method, RequestHandler handler);
-  void AddNotificationHandler(llvm::StringRef method,
-                              NotificationHandler handler);
-
 private:
   void AcceptCallback(std::unique_ptr<Socket> socket);
 
-  llvm::Expected<std::optional<lldb_protocol::mcp::Message>>
-  HandleData(llvm::StringRef data);
-
-  llvm::Expected<lldb_protocol::mcp::Response>
-  Handle(lldb_protocol::mcp::Request request);
-  void Handle(lldb_protocol::mcp::Notification notification);
-
-  llvm::Expected<lldb_protocol::mcp::Response>
-  InitializeHandler(const lldb_protocol::mcp::Request &);
-
-  llvm::Expected<lldb_protocol::mcp::Response>
-  ToolsListHandler(const lldb_protocol::mcp::Request &);
-  llvm::Expected<lldb_protocol::mcp::Response>
-  ToolsCallHandler(const lldb_protocol::mcp::Request &);
-
-  llvm::Expected<lldb_protocol::mcp::Response>
-  ResourcesListHandler(const lldb_protocol::mcp::Request &);
-  llvm::Expected<lldb_protocol::mcp::Response>
-  ResourcesReadHandler(const lldb_protocol::mcp::Request &);
-
-  lldb_protocol::mcp::Capabilities GetCapabilities();
-
-  llvm::StringLiteral kName = "lldb-mcp";
-  llvm::StringLiteral kVersion = "0.1.0";
+  lldb_protocol::mcp::Capabilities GetCapabilities() override;
 
   bool m_running = false;
 
@@ -98,14 +59,6 @@ class ProtocolServerMCP : public ProtocolServer {
   };
   llvm::Error ReadCallback(Client &client);
   std::vector<std::unique_ptr<Client>> m_clients;
-
-  std::mutex m_server_mutex;
-  llvm::StringMap<std::unique_ptr<lldb_protocol::mcp::Tool>> m_tools;
-  std::vector<std::unique_ptr<lldb_protocol::mcp::ResourceProvider>>
-      m_resource_providers;
-
-  llvm::StringMap<RequestHandler> m_request_handlers;
-  llvm::StringMap<NotificationHandler> m_notification_handlers;
 };
 } // namespace lldb_private::mcp
 

diff  --git a/lldb/source/Protocol/MCP/CMakeLists.txt 
b/lldb/source/Protocol/MCP/CMakeLists.txt
index f1b1098e064a5..a73e7e6a7cab1 100644
--- a/lldb/source/Protocol/MCP/CMakeLists.txt
+++ b/lldb/source/Protocol/MCP/CMakeLists.txt
@@ -1,6 +1,7 @@
 add_lldb_library(lldbProtocolMCP NO_PLUGIN_DEPENDENCIES
   MCPError.cpp
   Protocol.cpp
+  Server.cpp
   Tool.cpp
 
   LINK_COMPONENTS

diff  --git a/lldb/source/Protocol/MCP/Server.cpp 
b/lldb/source/Protocol/MCP/Server.cpp
new file mode 100644
index 0000000000000..4ec127fe75bdd
--- /dev/null
+++ b/lldb/source/Protocol/MCP/Server.cpp
@@ -0,0 +1,236 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Protocol/MCP/Server.h"
+#include "lldb/Protocol/MCP/MCPError.h"
+
+using namespace lldb_protocol::mcp;
+using namespace llvm;
+
+Server::Server(std::string name, std::string version)
+    : m_name(std::move(name)), m_version(std::move(version)) {
+  AddRequestHandlers();
+}
+
+void Server::AddRequestHandlers() {
+  AddRequestHandler("initialize", std::bind(&Server::InitializeHandler, this,
+                                            std::placeholders::_1));
+  AddRequestHandler("tools/list", std::bind(&Server::ToolsListHandler, this,
+                                            std::placeholders::_1));
+  AddRequestHandler("tools/call", std::bind(&Server::ToolsCallHandler, this,
+                                            std::placeholders::_1));
+  AddRequestHandler("resources/list", std::bind(&Server::ResourcesListHandler,
+                                                this, std::placeholders::_1));
+  AddRequestHandler("resources/read", std::bind(&Server::ResourcesReadHandler,
+                                                this, std::placeholders::_1));
+}
+
+llvm::Expected<Response> Server::Handle(Request request) {
+  auto it = m_request_handlers.find(request.method);
+  if (it != m_request_handlers.end()) {
+    llvm::Expected<Response> response = it->second(request);
+    if (!response)
+      return response;
+    response->id = request.id;
+    return *response;
+  }
+
+  return llvm::make_error<MCPError>(
+      llvm::formatv("no handler for request: {0}", request.method).str());
+}
+
+void Server::Handle(Notification notification) {
+  auto it = m_notification_handlers.find(notification.method);
+  if (it != m_notification_handlers.end()) {
+    it->second(notification);
+    return;
+  }
+}
+
+llvm::Expected<std::optional<Message>>
+Server::HandleData(llvm::StringRef data) {
+  auto message = llvm::json::parse<Message>(/*JSON=*/data);
+  if (!message)
+    return message.takeError();
+
+  if (const Request *request = std::get_if<Request>(&(*message))) {
+    llvm::Expected<Response> response = Handle(*request);
+
+    // Handle failures by converting them into an Error message.
+    if (!response) {
+      Error protocol_error;
+      llvm::handleAllErrors(
+          response.takeError(),
+          [&](const MCPError &err) { protocol_error = err.toProtcolError(); },
+          [&](const llvm::ErrorInfoBase &err) {
+            protocol_error.error.code = MCPError::kInternalError;
+            protocol_error.error.message = err.message();
+          });
+      protocol_error.id = request->id;
+      return protocol_error;
+    }
+
+    return *response;
+  }
+
+  if (const Notification *notification =
+          std::get_if<Notification>(&(*message))) {
+    Handle(*notification);
+    return std::nullopt;
+  }
+
+  if (std::get_if<Error>(&(*message)))
+    return llvm::createStringError("unexpected MCP message: error");
+
+  if (std::get_if<Response>(&(*message)))
+    return llvm::createStringError("unexpected MCP message: response");
+
+  llvm_unreachable("all message types handled");
+}
+
+void Server::AddTool(std::unique_ptr<Tool> tool) {
+  std::lock_guard<std::mutex> guard(m_mutex);
+
+  if (!tool)
+    return;
+  m_tools[tool->GetName()] = std::move(tool);
+}
+
+void Server::AddResourceProvider(
+    std::unique_ptr<ResourceProvider> resource_provider) {
+  std::lock_guard<std::mutex> guard(m_mutex);
+
+  if (!resource_provider)
+    return;
+  m_resource_providers.push_back(std::move(resource_provider));
+}
+
+void Server::AddRequestHandler(llvm::StringRef method, RequestHandler handler) 
{
+  std::lock_guard<std::mutex> guard(m_mutex);
+  m_request_handlers[method] = std::move(handler);
+}
+
+void Server::AddNotificationHandler(llvm::StringRef method,
+                                    NotificationHandler handler) {
+  std::lock_guard<std::mutex> guard(m_mutex);
+  m_notification_handlers[method] = std::move(handler);
+}
+
+llvm::Expected<Response> Server::InitializeHandler(const Request &request) {
+  Response response;
+  response.result.emplace(llvm::json::Object{
+      {"protocolVersion", mcp::kProtocolVersion},
+      {"capabilities", GetCapabilities()},
+      {"serverInfo",
+       llvm::json::Object{{"name", m_name}, {"version", m_version}}}});
+  return response;
+}
+
+llvm::Expected<Response> Server::ToolsListHandler(const Request &request) {
+  Response response;
+
+  llvm::json::Array tools;
+  for (const auto &tool : m_tools)
+    tools.emplace_back(toJSON(tool.second->GetDefinition()));
+
+  response.result.emplace(llvm::json::Object{{"tools", std::move(tools)}});
+
+  return response;
+}
+
+llvm::Expected<Response> Server::ToolsCallHandler(const Request &request) {
+  Response response;
+
+  if (!request.params)
+    return llvm::createStringError("no tool parameters");
+
+  const json::Object *param_obj = request.params->getAsObject();
+  if (!param_obj)
+    return llvm::createStringError("no tool parameters");
+
+  const json::Value *name = param_obj->get("name");
+  if (!name)
+    return llvm::createStringError("no tool name");
+
+  llvm::StringRef tool_name = name->getAsString().value_or("");
+  if (tool_name.empty())
+    return llvm::createStringError("no tool name");
+
+  auto it = m_tools.find(tool_name);
+  if (it == m_tools.end())
+    return llvm::createStringError(llvm::formatv("no tool \"{0}\"", 
tool_name));
+
+  ToolArguments tool_args;
+  if (const json::Value *args = param_obj->get("arguments"))
+    tool_args = *args;
+
+  llvm::Expected<TextResult> text_result = it->second->Call(tool_args);
+  if (!text_result)
+    return text_result.takeError();
+
+  response.result.emplace(toJSON(*text_result));
+
+  return response;
+}
+
+llvm::Expected<Response> Server::ResourcesListHandler(const Request &request) {
+  Response response;
+
+  llvm::json::Array resources;
+
+  std::lock_guard<std::mutex> guard(m_mutex);
+  for (std::unique_ptr<ResourceProvider> &resource_provider_up :
+       m_resource_providers) {
+    for (const Resource &resource : resource_provider_up->GetResources())
+      resources.push_back(resource);
+  }
+  response.result.emplace(
+      llvm::json::Object{{"resources", std::move(resources)}});
+
+  return response;
+}
+
+llvm::Expected<Response> Server::ResourcesReadHandler(const Request &request) {
+  Response response;
+
+  if (!request.params)
+    return llvm::createStringError("no resource parameters");
+
+  const json::Object *param_obj = request.params->getAsObject();
+  if (!param_obj)
+    return llvm::createStringError("no resource parameters");
+
+  const json::Value *uri = param_obj->get("uri");
+  if (!uri)
+    return llvm::createStringError("no resource uri");
+
+  llvm::StringRef uri_str = uri->getAsString().value_or("");
+  if (uri_str.empty())
+    return llvm::createStringError("no resource uri");
+
+  std::lock_guard<std::mutex> guard(m_mutex);
+  for (std::unique_ptr<ResourceProvider> &resource_provider_up :
+       m_resource_providers) {
+    llvm::Expected<ResourceResult> result =
+        resource_provider_up->ReadResource(uri_str);
+    if (result.errorIsA<UnsupportedURI>()) {
+      llvm::consumeError(result.takeError());
+      continue;
+    }
+    if (!result)
+      return result.takeError();
+
+    Response response;
+    response.result.emplace(std::move(*result));
+    return response;
+  }
+
+  return make_error<MCPError>(
+      llvm::formatv("no resource handler for uri: {0}", uri_str).str(),
+      MCPError::kResourceNotFound);
+}


        
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to