[lldb] Move MCP protocol into its own library (NFC) (#152059)
This PR moves the MCP protocol code into its own library (`lldbProtocolMCP`) so the code can be shared between the `ProtocolServerMCP` plugin in LLDB as well as `lldb-mcp`. The goal is to do the same thing for DAP (which, for now, would be used exclusively from `lldb-dap`). To make it clear that it's neither part of the `lldb` nor the `lldb_private` namespace, I created a new `lldb_protocol` namespace. Depending on how much code would be reused by lldb-dap, we may move more code into the protocol library.
This commit is contained in:
parent
1b651bf2b7
commit
ed294c28ac
@ -11,15 +11,15 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLDB_PLUGINS_PROTOCOL_MCP_PROTOCOL_H
|
||||
#define LLDB_PLUGINS_PROTOCOL_MCP_PROTOCOL_H
|
||||
#ifndef LLDB_PROTOCOL_MCP_PROTOCOL_H
|
||||
#define LLDB_PROTOCOL_MCP_PROTOCOL_H
|
||||
|
||||
#include "llvm/Support/JSON.h"
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <variant>
|
||||
|
||||
namespace lldb_private::mcp::protocol {
|
||||
namespace lldb_protocol::mcp {
|
||||
|
||||
static llvm::StringLiteral kVersion = "2024-11-05";
|
||||
|
||||
@ -183,6 +183,6 @@ llvm::json::Value toJSON(const Message &);
|
||||
|
||||
using ToolArguments = std::variant<std::monostate, llvm::json::Value>;
|
||||
|
||||
} // namespace lldb_private::mcp::protocol
|
||||
} // namespace lldb_protocol::mcp
|
||||
|
||||
#endif
|
@ -10,6 +10,7 @@ add_subdirectory(Host)
|
||||
add_subdirectory(Initialization)
|
||||
add_subdirectory(Interpreter)
|
||||
add_subdirectory(Plugins)
|
||||
add_subdirectory(Protocol)
|
||||
add_subdirectory(Symbol)
|
||||
add_subdirectory(Target)
|
||||
add_subdirectory(Utility)
|
||||
|
@ -1,6 +1,5 @@
|
||||
add_lldb_library(lldbPluginProtocolServerMCP PLUGIN
|
||||
MCPError.cpp
|
||||
Protocol.cpp
|
||||
ProtocolServerMCP.cpp
|
||||
Resource.cpp
|
||||
Tool.cpp
|
||||
@ -10,5 +9,6 @@ add_lldb_library(lldbPluginProtocolServerMCP PLUGIN
|
||||
|
||||
LINK_LIBS
|
||||
lldbHost
|
||||
lldbProtocolMCP
|
||||
lldbUtility
|
||||
)
|
||||
|
@ -11,7 +11,7 @@
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include <system_error>
|
||||
|
||||
namespace lldb_private::mcp {
|
||||
using namespace lldb_private::mcp;
|
||||
|
||||
char MCPError::ID;
|
||||
char UnsupportedURI::ID;
|
||||
@ -25,8 +25,8 @@ std::error_code MCPError::convertToErrorCode() const {
|
||||
return llvm::inconvertibleErrorCode();
|
||||
}
|
||||
|
||||
protocol::Error MCPError::toProtcolError() const {
|
||||
protocol::Error error;
|
||||
lldb_protocol::mcp::Error MCPError::toProtcolError() const {
|
||||
lldb_protocol::mcp::Error error;
|
||||
error.error.code = m_error_code;
|
||||
error.error.message = m_message;
|
||||
return error;
|
||||
@ -41,5 +41,3 @@ void UnsupportedURI::log(llvm::raw_ostream &OS) const {
|
||||
std::error_code UnsupportedURI::convertToErrorCode() const {
|
||||
return llvm::inconvertibleErrorCode();
|
||||
}
|
||||
|
||||
} // namespace lldb_private::mcp
|
||||
|
@ -6,7 +6,7 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "Protocol.h"
|
||||
#include "lldb/Protocol/MCP/Protocol.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
#include "llvm/Support/FormatVariadic.h"
|
||||
#include <string>
|
||||
@ -24,7 +24,7 @@ public:
|
||||
|
||||
const std::string &getMessage() const { return m_message; }
|
||||
|
||||
protocol::Error toProtcolError() const;
|
||||
lldb_protocol::mcp::Error toProtcolError() const;
|
||||
|
||||
static constexpr int64_t kResourceNotFound = -32002;
|
||||
static constexpr int64_t kInternalError = -32603;
|
||||
|
@ -42,10 +42,11 @@ ProtocolServerMCP::ProtocolServerMCP() : ProtocolServer() {
|
||||
AddRequestHandler("resources/read",
|
||||
std::bind(&ProtocolServerMCP::ResourcesReadHandler, this,
|
||||
std::placeholders::_1));
|
||||
AddNotificationHandler(
|
||||
"notifications/initialized", [](const protocol::Notification &) {
|
||||
LLDB_LOG(GetLog(LLDBLog::Host), "MCP initialization complete");
|
||||
});
|
||||
AddNotificationHandler("notifications/initialized",
|
||||
[](const lldb_protocol::mcp::Notification &) {
|
||||
LLDB_LOG(GetLog(LLDBLog::Host),
|
||||
"MCP initialization complete");
|
||||
});
|
||||
|
||||
AddTool(
|
||||
std::make_unique<CommandTool>("lldb_command", "Run an lldb command."));
|
||||
@ -72,11 +73,11 @@ llvm::StringRef ProtocolServerMCP::GetPluginDescriptionStatic() {
|
||||
return "MCP Server.";
|
||||
}
|
||||
|
||||
llvm::Expected<protocol::Response>
|
||||
ProtocolServerMCP::Handle(protocol::Request request) {
|
||||
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<protocol::Response> response = it->second(request);
|
||||
llvm::Expected<lldb_protocol::mcp::Response> response = it->second(request);
|
||||
if (!response)
|
||||
return response;
|
||||
response->id = request.id;
|
||||
@ -87,7 +88,7 @@ ProtocolServerMCP::Handle(protocol::Request request) {
|
||||
llvm::formatv("no handler for request: {0}", request.method).str());
|
||||
}
|
||||
|
||||
void ProtocolServerMCP::Handle(protocol::Notification notification) {
|
||||
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);
|
||||
@ -133,7 +134,7 @@ llvm::Error ProtocolServerMCP::ReadCallback(Client &client) {
|
||||
|
||||
for (std::string::size_type pos;
|
||||
(pos = client.buffer.find('\n')) != std::string::npos;) {
|
||||
llvm::Expected<std::optional<protocol::Message>> message =
|
||||
llvm::Expected<std::optional<lldb_protocol::mcp::Message>> message =
|
||||
HandleData(StringRef(client.buffer.data(), pos));
|
||||
client.buffer = client.buffer.erase(0, pos + 1);
|
||||
if (!message)
|
||||
@ -208,19 +209,19 @@ llvm::Error ProtocolServerMCP::Stop() {
|
||||
return llvm::Error::success();
|
||||
}
|
||||
|
||||
llvm::Expected<std::optional<protocol::Message>>
|
||||
llvm::Expected<std::optional<lldb_protocol::mcp::Message>>
|
||||
ProtocolServerMCP::HandleData(llvm::StringRef data) {
|
||||
auto message = llvm::json::parse<protocol::Message>(/*JSON=*/data);
|
||||
auto message = llvm::json::parse<lldb_protocol::mcp::Message>(/*JSON=*/data);
|
||||
if (!message)
|
||||
return message.takeError();
|
||||
|
||||
if (const protocol::Request *request =
|
||||
std::get_if<protocol::Request>(&(*message))) {
|
||||
llvm::Expected<protocol::Response> response = Handle(*request);
|
||||
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) {
|
||||
protocol::Error protocol_error;
|
||||
lldb_protocol::mcp::Error protocol_error;
|
||||
llvm::handleAllErrors(
|
||||
response.takeError(),
|
||||
[&](const MCPError &err) { protocol_error = err.toProtcolError(); },
|
||||
@ -235,23 +236,23 @@ ProtocolServerMCP::HandleData(llvm::StringRef data) {
|
||||
return *response;
|
||||
}
|
||||
|
||||
if (const protocol::Notification *notification =
|
||||
std::get_if<protocol::Notification>(&(*message))) {
|
||||
if (const lldb_protocol::mcp::Notification *notification =
|
||||
std::get_if<lldb_protocol::mcp::Notification>(&(*message))) {
|
||||
Handle(*notification);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
if (std::get_if<protocol::Error>(&(*message)))
|
||||
if (std::get_if<lldb_protocol::mcp::Error>(&(*message)))
|
||||
return llvm::createStringError("unexpected MCP message: error");
|
||||
|
||||
if (std::get_if<protocol::Response>(&(*message)))
|
||||
if (std::get_if<lldb_protocol::mcp::Response>(&(*message)))
|
||||
return llvm::createStringError("unexpected MCP message: response");
|
||||
|
||||
llvm_unreachable("all message types handled");
|
||||
}
|
||||
|
||||
protocol::Capabilities ProtocolServerMCP::GetCapabilities() {
|
||||
protocol::Capabilities capabilities;
|
||||
lldb_protocol::mcp::Capabilities ProtocolServerMCP::GetCapabilities() {
|
||||
lldb_protocol::mcp::Capabilities capabilities;
|
||||
capabilities.tools.listChanged = true;
|
||||
// FIXME: Support sending notifications when a debugger/target are
|
||||
// added/removed.
|
||||
@ -288,20 +289,22 @@ void ProtocolServerMCP::AddNotificationHandler(llvm::StringRef method,
|
||||
m_notification_handlers[method] = std::move(handler);
|
||||
}
|
||||
|
||||
llvm::Expected<protocol::Response>
|
||||
ProtocolServerMCP::InitializeHandler(const protocol::Request &request) {
|
||||
protocol::Response response;
|
||||
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", protocol::kVersion},
|
||||
{"protocolVersion", lldb_protocol::mcp::kVersion},
|
||||
{"capabilities", GetCapabilities()},
|
||||
{"serverInfo",
|
||||
llvm::json::Object{{"name", kName}, {"version", kVersion}}}});
|
||||
return response;
|
||||
}
|
||||
|
||||
llvm::Expected<protocol::Response>
|
||||
ProtocolServerMCP::ToolsListHandler(const protocol::Request &request) {
|
||||
protocol::Response 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)
|
||||
@ -312,9 +315,10 @@ ProtocolServerMCP::ToolsListHandler(const protocol::Request &request) {
|
||||
return response;
|
||||
}
|
||||
|
||||
llvm::Expected<protocol::Response>
|
||||
ProtocolServerMCP::ToolsCallHandler(const protocol::Request &request) {
|
||||
protocol::Response 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");
|
||||
@ -335,11 +339,11 @@ ProtocolServerMCP::ToolsCallHandler(const protocol::Request &request) {
|
||||
if (it == m_tools.end())
|
||||
return llvm::createStringError(llvm::formatv("no tool \"{0}\"", tool_name));
|
||||
|
||||
protocol::ToolArguments tool_args;
|
||||
lldb_protocol::mcp::ToolArguments tool_args;
|
||||
if (const json::Value *args = param_obj->get("arguments"))
|
||||
tool_args = *args;
|
||||
|
||||
llvm::Expected<protocol::TextResult> text_result =
|
||||
llvm::Expected<lldb_protocol::mcp::TextResult> text_result =
|
||||
it->second->Call(tool_args);
|
||||
if (!text_result)
|
||||
return text_result.takeError();
|
||||
@ -349,16 +353,17 @@ ProtocolServerMCP::ToolsCallHandler(const protocol::Request &request) {
|
||||
return response;
|
||||
}
|
||||
|
||||
llvm::Expected<protocol::Response>
|
||||
ProtocolServerMCP::ResourcesListHandler(const protocol::Request &request) {
|
||||
protocol::Response 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 protocol::Resource &resource :
|
||||
for (const lldb_protocol::mcp::Resource &resource :
|
||||
resource_provider_up->GetResources())
|
||||
resources.push_back(resource);
|
||||
}
|
||||
@ -368,9 +373,10 @@ ProtocolServerMCP::ResourcesListHandler(const protocol::Request &request) {
|
||||
return response;
|
||||
}
|
||||
|
||||
llvm::Expected<protocol::Response>
|
||||
ProtocolServerMCP::ResourcesReadHandler(const protocol::Request &request) {
|
||||
protocol::Response 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");
|
||||
@ -390,7 +396,7 @@ ProtocolServerMCP::ResourcesReadHandler(const protocol::Request &request) {
|
||||
std::lock_guard<std::mutex> guard(m_server_mutex);
|
||||
for (std::unique_ptr<ResourceProvider> &resource_provider_up :
|
||||
m_resource_providers) {
|
||||
llvm::Expected<protocol::ResourceResult> result =
|
||||
llvm::Expected<lldb_protocol::mcp::ResourceResult> result =
|
||||
resource_provider_up->ReadResource(uri_str);
|
||||
if (result.errorIsA<UnsupportedURI>()) {
|
||||
llvm::consumeError(result.takeError());
|
||||
@ -399,7 +405,7 @@ ProtocolServerMCP::ResourcesReadHandler(const protocol::Request &request) {
|
||||
if (!result)
|
||||
return result.takeError();
|
||||
|
||||
protocol::Response response;
|
||||
lldb_protocol::mcp::Response response;
|
||||
response.result.emplace(std::move(*result));
|
||||
return response;
|
||||
}
|
||||
|
@ -9,12 +9,12 @@
|
||||
#ifndef LLDB_PLUGINS_PROTOCOL_MCP_PROTOCOLSERVERMCP_H
|
||||
#define LLDB_PLUGINS_PROTOCOL_MCP_PROTOCOLSERVERMCP_H
|
||||
|
||||
#include "Protocol.h"
|
||||
#include "Resource.h"
|
||||
#include "Tool.h"
|
||||
#include "lldb/Core/ProtocolServer.h"
|
||||
#include "lldb/Host/MainLoop.h"
|
||||
#include "lldb/Host/Socket.h"
|
||||
#include "lldb/Protocol/MCP/Protocol.h"
|
||||
#include "llvm/ADT/StringMap.h"
|
||||
#include <thread>
|
||||
|
||||
@ -41,10 +41,11 @@ public:
|
||||
Socket *GetSocket() const override { return m_listener.get(); }
|
||||
|
||||
protected:
|
||||
using RequestHandler = std::function<llvm::Expected<protocol::Response>(
|
||||
const protocol::Request &)>;
|
||||
using RequestHandler =
|
||||
std::function<llvm::Expected<lldb_protocol::mcp::Response>(
|
||||
const lldb_protocol::mcp::Request &)>;
|
||||
using NotificationHandler =
|
||||
std::function<void(const protocol::Notification &)>;
|
||||
std::function<void(const lldb_protocol::mcp::Notification &)>;
|
||||
|
||||
void AddTool(std::unique_ptr<Tool> tool);
|
||||
void AddResourceProvider(std::unique_ptr<ResourceProvider> resource_provider);
|
||||
@ -56,26 +57,27 @@ protected:
|
||||
private:
|
||||
void AcceptCallback(std::unique_ptr<Socket> socket);
|
||||
|
||||
llvm::Expected<std::optional<protocol::Message>>
|
||||
llvm::Expected<std::optional<lldb_protocol::mcp::Message>>
|
||||
HandleData(llvm::StringRef data);
|
||||
|
||||
llvm::Expected<protocol::Response> Handle(protocol::Request request);
|
||||
void Handle(protocol::Notification notification);
|
||||
llvm::Expected<lldb_protocol::mcp::Response>
|
||||
Handle(lldb_protocol::mcp::Request request);
|
||||
void Handle(lldb_protocol::mcp::Notification notification);
|
||||
|
||||
llvm::Expected<protocol::Response>
|
||||
InitializeHandler(const protocol::Request &);
|
||||
llvm::Expected<lldb_protocol::mcp::Response>
|
||||
InitializeHandler(const lldb_protocol::mcp::Request &);
|
||||
|
||||
llvm::Expected<protocol::Response>
|
||||
ToolsListHandler(const protocol::Request &);
|
||||
llvm::Expected<protocol::Response>
|
||||
ToolsCallHandler(const protocol::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<protocol::Response>
|
||||
ResourcesListHandler(const protocol::Request &);
|
||||
llvm::Expected<protocol::Response>
|
||||
ResourcesReadHandler(const protocol::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 &);
|
||||
|
||||
protocol::Capabilities GetCapabilities();
|
||||
lldb_protocol::mcp::Capabilities GetCapabilities();
|
||||
|
||||
llvm::StringLiteral kName = "lldb-mcp";
|
||||
llvm::StringLiteral kVersion = "0.1.0";
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "lldb/Core/Module.h"
|
||||
#include "lldb/Target/Platform.h"
|
||||
|
||||
using namespace lldb_private;
|
||||
using namespace lldb_private::mcp;
|
||||
|
||||
namespace {
|
||||
@ -64,11 +65,11 @@ static llvm::Error createUnsupportedURIError(llvm::StringRef uri) {
|
||||
return llvm::make_error<UnsupportedURI>(uri.str());
|
||||
}
|
||||
|
||||
protocol::Resource
|
||||
lldb_protocol::mcp::Resource
|
||||
DebuggerResourceProvider::GetDebuggerResource(Debugger &debugger) {
|
||||
const lldb::user_id_t debugger_id = debugger.GetID();
|
||||
|
||||
protocol::Resource resource;
|
||||
lldb_protocol::mcp::Resource resource;
|
||||
resource.uri = llvm::formatv("lldb://debugger/{0}", debugger_id);
|
||||
resource.name = debugger.GetInstanceName();
|
||||
resource.description =
|
||||
@ -78,7 +79,7 @@ DebuggerResourceProvider::GetDebuggerResource(Debugger &debugger) {
|
||||
return resource;
|
||||
}
|
||||
|
||||
protocol::Resource
|
||||
lldb_protocol::mcp::Resource
|
||||
DebuggerResourceProvider::GetTargetResource(size_t target_idx, Target &target) {
|
||||
const size_t debugger_id = target.GetDebugger().GetID();
|
||||
|
||||
@ -87,7 +88,7 @@ DebuggerResourceProvider::GetTargetResource(size_t target_idx, Target &target) {
|
||||
if (Module *exe_module = target.GetExecutableModulePointer())
|
||||
target_name = exe_module->GetFileSpec().GetFilename().GetString();
|
||||
|
||||
protocol::Resource resource;
|
||||
lldb_protocol::mcp::Resource resource;
|
||||
resource.uri =
|
||||
llvm::formatv("lldb://debugger/{0}/target/{1}", debugger_id, target_idx);
|
||||
resource.name = target_name;
|
||||
@ -98,8 +99,9 @@ DebuggerResourceProvider::GetTargetResource(size_t target_idx, Target &target) {
|
||||
return resource;
|
||||
}
|
||||
|
||||
std::vector<protocol::Resource> DebuggerResourceProvider::GetResources() const {
|
||||
std::vector<protocol::Resource> resources;
|
||||
std::vector<lldb_protocol::mcp::Resource>
|
||||
DebuggerResourceProvider::GetResources() const {
|
||||
std::vector<lldb_protocol::mcp::Resource> resources;
|
||||
|
||||
const size_t num_debuggers = Debugger::GetNumDebuggers();
|
||||
for (size_t i = 0; i < num_debuggers; ++i) {
|
||||
@ -121,7 +123,7 @@ std::vector<protocol::Resource> DebuggerResourceProvider::GetResources() const {
|
||||
return resources;
|
||||
}
|
||||
|
||||
llvm::Expected<protocol::ResourceResult>
|
||||
llvm::Expected<lldb_protocol::mcp::ResourceResult>
|
||||
DebuggerResourceProvider::ReadResource(llvm::StringRef uri) const {
|
||||
|
||||
auto [protocol, path] = uri.split("://");
|
||||
@ -158,7 +160,7 @@ DebuggerResourceProvider::ReadResource(llvm::StringRef uri) const {
|
||||
return ReadDebuggerResource(uri, debugger_idx);
|
||||
}
|
||||
|
||||
llvm::Expected<protocol::ResourceResult>
|
||||
llvm::Expected<lldb_protocol::mcp::ResourceResult>
|
||||
DebuggerResourceProvider::ReadDebuggerResource(llvm::StringRef uri,
|
||||
lldb::user_id_t debugger_id) {
|
||||
lldb::DebuggerSP debugger_sp = Debugger::FindDebuggerWithID(debugger_id);
|
||||
@ -170,17 +172,17 @@ DebuggerResourceProvider::ReadDebuggerResource(llvm::StringRef uri,
|
||||
debugger_resource.name = debugger_sp->GetInstanceName();
|
||||
debugger_resource.num_targets = debugger_sp->GetTargetList().GetNumTargets();
|
||||
|
||||
protocol::ResourceContents contents;
|
||||
lldb_protocol::mcp::ResourceContents contents;
|
||||
contents.uri = uri;
|
||||
contents.mimeType = kMimeTypeJSON;
|
||||
contents.text = llvm::formatv("{0}", toJSON(debugger_resource));
|
||||
|
||||
protocol::ResourceResult result;
|
||||
lldb_protocol::mcp::ResourceResult result;
|
||||
result.contents.push_back(contents);
|
||||
return result;
|
||||
}
|
||||
|
||||
llvm::Expected<protocol::ResourceResult>
|
||||
llvm::Expected<lldb_protocol::mcp::ResourceResult>
|
||||
DebuggerResourceProvider::ReadTargetResource(llvm::StringRef uri,
|
||||
lldb::user_id_t debugger_id,
|
||||
size_t target_idx) {
|
||||
@ -206,12 +208,12 @@ DebuggerResourceProvider::ReadTargetResource(llvm::StringRef uri,
|
||||
if (lldb::PlatformSP platform_sp = target_sp->GetPlatform())
|
||||
target_resource.platform = platform_sp->GetName();
|
||||
|
||||
protocol::ResourceContents contents;
|
||||
lldb_protocol::mcp::ResourceContents contents;
|
||||
contents.uri = uri;
|
||||
contents.mimeType = kMimeTypeJSON;
|
||||
contents.text = llvm::formatv("{0}", toJSON(target_resource));
|
||||
|
||||
protocol::ResourceResult result;
|
||||
lldb_protocol::mcp::ResourceResult result;
|
||||
result.contents.push_back(contents);
|
||||
return result;
|
||||
}
|
||||
|
@ -9,7 +9,7 @@
|
||||
#ifndef LLDB_PLUGINS_PROTOCOL_MCP_RESOURCE_H
|
||||
#define LLDB_PLUGINS_PROTOCOL_MCP_RESOURCE_H
|
||||
|
||||
#include "Protocol.h"
|
||||
#include "lldb/Protocol/MCP/Protocol.h"
|
||||
#include "lldb/lldb-private.h"
|
||||
#include <vector>
|
||||
|
||||
@ -20,8 +20,8 @@ public:
|
||||
ResourceProvider() = default;
|
||||
virtual ~ResourceProvider() = default;
|
||||
|
||||
virtual std::vector<protocol::Resource> GetResources() const = 0;
|
||||
virtual llvm::Expected<protocol::ResourceResult>
|
||||
virtual std::vector<lldb_protocol::mcp::Resource> GetResources() const = 0;
|
||||
virtual llvm::Expected<lldb_protocol::mcp::ResourceResult>
|
||||
ReadResource(llvm::StringRef uri) const = 0;
|
||||
};
|
||||
|
||||
@ -30,18 +30,19 @@ public:
|
||||
using ResourceProvider::ResourceProvider;
|
||||
virtual ~DebuggerResourceProvider() = default;
|
||||
|
||||
virtual std::vector<protocol::Resource> GetResources() const override;
|
||||
virtual llvm::Expected<protocol::ResourceResult>
|
||||
virtual std::vector<lldb_protocol::mcp::Resource>
|
||||
GetResources() const override;
|
||||
virtual llvm::Expected<lldb_protocol::mcp::ResourceResult>
|
||||
ReadResource(llvm::StringRef uri) const override;
|
||||
|
||||
private:
|
||||
static protocol::Resource GetDebuggerResource(Debugger &debugger);
|
||||
static protocol::Resource GetTargetResource(size_t target_idx,
|
||||
Target &target);
|
||||
static lldb_protocol::mcp::Resource GetDebuggerResource(Debugger &debugger);
|
||||
static lldb_protocol::mcp::Resource GetTargetResource(size_t target_idx,
|
||||
Target &target);
|
||||
|
||||
static llvm::Expected<protocol::ResourceResult>
|
||||
static llvm::Expected<lldb_protocol::mcp::ResourceResult>
|
||||
ReadDebuggerResource(llvm::StringRef uri, lldb::user_id_t debugger_id);
|
||||
static llvm::Expected<protocol::ResourceResult>
|
||||
static llvm::Expected<lldb_protocol::mcp::ResourceResult>
|
||||
ReadTargetResource(llvm::StringRef uri, lldb::user_id_t debugger_id,
|
||||
size_t target_idx);
|
||||
};
|
||||
|
@ -11,6 +11,8 @@
|
||||
#include "lldb/Interpreter/CommandInterpreter.h"
|
||||
#include "lldb/Interpreter/CommandReturnObject.h"
|
||||
|
||||
using namespace lldb_private;
|
||||
using namespace lldb_protocol;
|
||||
using namespace lldb_private::mcp;
|
||||
using namespace llvm;
|
||||
|
||||
@ -28,11 +30,11 @@ bool fromJSON(const llvm::json::Value &V, CommandToolArguments &A,
|
||||
}
|
||||
|
||||
/// Helper function to create a TextResult from a string output.
|
||||
static lldb_private::mcp::protocol::TextResult
|
||||
createTextResult(std::string output, bool is_error = false) {
|
||||
lldb_private::mcp::protocol::TextResult text_result;
|
||||
static lldb_protocol::mcp::TextResult createTextResult(std::string output,
|
||||
bool is_error = false) {
|
||||
lldb_protocol::mcp::TextResult text_result;
|
||||
text_result.content.emplace_back(
|
||||
lldb_private::mcp::protocol::TextContent{{std::move(output)}});
|
||||
lldb_protocol::mcp::TextContent{{std::move(output)}});
|
||||
text_result.isError = is_error;
|
||||
return text_result;
|
||||
}
|
||||
@ -42,8 +44,8 @@ createTextResult(std::string output, bool is_error = false) {
|
||||
Tool::Tool(std::string name, std::string description)
|
||||
: m_name(std::move(name)), m_description(std::move(description)) {}
|
||||
|
||||
protocol::ToolDefinition Tool::GetDefinition() const {
|
||||
protocol::ToolDefinition definition;
|
||||
lldb_protocol::mcp::ToolDefinition Tool::GetDefinition() const {
|
||||
lldb_protocol::mcp::ToolDefinition definition;
|
||||
definition.name = m_name;
|
||||
definition.description = m_description;
|
||||
|
||||
@ -53,8 +55,8 @@ protocol::ToolDefinition Tool::GetDefinition() const {
|
||||
return definition;
|
||||
}
|
||||
|
||||
llvm::Expected<protocol::TextResult>
|
||||
CommandTool::Call(const protocol::ToolArguments &args) {
|
||||
llvm::Expected<lldb_protocol::mcp::TextResult>
|
||||
CommandTool::Call(const lldb_protocol::mcp::ToolArguments &args) {
|
||||
if (!std::holds_alternative<json::Value>(args))
|
||||
return createStringError("CommandTool requires arguments");
|
||||
|
||||
|
@ -9,8 +9,8 @@
|
||||
#ifndef LLDB_PLUGINS_PROTOCOL_MCP_TOOL_H
|
||||
#define LLDB_PLUGINS_PROTOCOL_MCP_TOOL_H
|
||||
|
||||
#include "Protocol.h"
|
||||
#include "lldb/Core/Debugger.h"
|
||||
#include "lldb/Protocol/MCP/Protocol.h"
|
||||
#include "llvm/Support/JSON.h"
|
||||
#include <string>
|
||||
|
||||
@ -21,14 +21,14 @@ public:
|
||||
Tool(std::string name, std::string description);
|
||||
virtual ~Tool() = default;
|
||||
|
||||
virtual llvm::Expected<protocol::TextResult>
|
||||
Call(const protocol::ToolArguments &args) = 0;
|
||||
virtual llvm::Expected<lldb_protocol::mcp::TextResult>
|
||||
Call(const lldb_protocol::mcp::ToolArguments &args) = 0;
|
||||
|
||||
virtual std::optional<llvm::json::Value> GetSchema() const {
|
||||
return llvm::json::Object{{"type", "object"}};
|
||||
}
|
||||
|
||||
protocol::ToolDefinition GetDefinition() const;
|
||||
lldb_protocol::mcp::ToolDefinition GetDefinition() const;
|
||||
|
||||
const std::string &GetName() { return m_name; }
|
||||
|
||||
@ -42,8 +42,8 @@ public:
|
||||
using mcp::Tool::Tool;
|
||||
~CommandTool() = default;
|
||||
|
||||
virtual llvm::Expected<protocol::TextResult>
|
||||
Call(const protocol::ToolArguments &args) override;
|
||||
virtual llvm::Expected<lldb_protocol::mcp::TextResult>
|
||||
Call(const lldb_protocol::mcp::ToolArguments &args) override;
|
||||
|
||||
virtual std::optional<llvm::json::Value> GetSchema() const override;
|
||||
};
|
||||
|
1
lldb/source/Protocol/CMakeLists.txt
Normal file
1
lldb/source/Protocol/CMakeLists.txt
Normal file
@ -0,0 +1 @@
|
||||
add_subdirectory(MCP)
|
8
lldb/source/Protocol/MCP/CMakeLists.txt
Normal file
8
lldb/source/Protocol/MCP/CMakeLists.txt
Normal file
@ -0,0 +1,8 @@
|
||||
add_lldb_library(lldbProtocolMCP NO_PLUGIN_DEPENDENCIES
|
||||
Protocol.cpp
|
||||
|
||||
LINK_COMPONENTS
|
||||
Support
|
||||
LINK_LIBS
|
||||
lldbUtility
|
||||
)
|
@ -6,12 +6,12 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "Protocol.h"
|
||||
#include "lldb/Protocol/MCP/Protocol.h"
|
||||
#include "llvm/Support/JSON.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
namespace lldb_private::mcp::protocol {
|
||||
namespace lldb_protocol::mcp {
|
||||
|
||||
static bool mapRaw(const json::Value &Params, StringLiteral Prop,
|
||||
std::optional<json::Value> &V, json::Path P) {
|
||||
@ -228,7 +228,7 @@ bool fromJSON(const llvm::json::Value &V, Message &M, llvm::json::Path P) {
|
||||
|
||||
// A message without an ID is a Notification.
|
||||
if (!O->get("id")) {
|
||||
protocol::Notification N;
|
||||
Notification N;
|
||||
if (!fromJSON(V, N, P))
|
||||
return false;
|
||||
M = std::move(N);
|
||||
@ -236,7 +236,7 @@ bool fromJSON(const llvm::json::Value &V, Message &M, llvm::json::Path P) {
|
||||
}
|
||||
|
||||
if (O->get("error")) {
|
||||
protocol::Error E;
|
||||
Error E;
|
||||
if (!fromJSON(V, E, P))
|
||||
return false;
|
||||
M = std::move(E);
|
||||
@ -244,7 +244,7 @@ bool fromJSON(const llvm::json::Value &V, Message &M, llvm::json::Path P) {
|
||||
}
|
||||
|
||||
if (O->get("result")) {
|
||||
protocol::Response R;
|
||||
Response R;
|
||||
if (!fromJSON(V, R, P))
|
||||
return false;
|
||||
M = std::move(R);
|
||||
@ -252,7 +252,7 @@ bool fromJSON(const llvm::json::Value &V, Message &M, llvm::json::Path P) {
|
||||
}
|
||||
|
||||
if (O->get("method")) {
|
||||
protocol::Request R;
|
||||
Request R;
|
||||
if (!fromJSON(V, R, P))
|
||||
return false;
|
||||
M = std::move(R);
|
||||
@ -263,4 +263,4 @@ bool fromJSON(const llvm::json::Value &V, Message &M, llvm::json::Path P) {
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace lldb_private::mcp::protocol
|
||||
} // namespace lldb_protocol::mcp
|
@ -61,25 +61,26 @@ add_subdirectory(Disassembler)
|
||||
add_subdirectory(Editline)
|
||||
add_subdirectory(Expression)
|
||||
add_subdirectory(Host)
|
||||
add_subdirectory(Interpreter)
|
||||
add_subdirectory(Instruction)
|
||||
add_subdirectory(Interpreter)
|
||||
add_subdirectory(Language)
|
||||
add_subdirectory(ObjectFile)
|
||||
add_subdirectory(Platform)
|
||||
add_subdirectory(Process)
|
||||
add_subdirectory(Protocol)
|
||||
add_subdirectory(ScriptInterpreter)
|
||||
add_subdirectory(Signals)
|
||||
add_subdirectory(Symbol)
|
||||
add_subdirectory(SymbolFile)
|
||||
add_subdirectory(Target)
|
||||
add_subdirectory(tools)
|
||||
add_subdirectory(Thread)
|
||||
add_subdirectory(UnwindAssembly)
|
||||
add_subdirectory(Utility)
|
||||
add_subdirectory(Thread)
|
||||
add_subdirectory(ValueObject)
|
||||
add_subdirectory(tools)
|
||||
|
||||
if(LLDB_ENABLE_PROTOCOL_SERVERS)
|
||||
add_subdirectory(Protocol)
|
||||
add_subdirectory(ProtocolServer)
|
||||
endif()
|
||||
|
||||
if(LLDB_CAN_USE_DEBUGSERVER AND LLDB_TOOL_DEBUGSERVER_BUILD AND NOT LLDB_USE_SYSTEM_DEBUGSERVER)
|
||||
|
@ -1,12 +1,9 @@
|
||||
add_lldb_unittest(ProtocolTests
|
||||
ProtocolMCPTest.cpp
|
||||
ProtocolMCPServerTest.cpp
|
||||
|
||||
LINK_LIBS
|
||||
lldbCore
|
||||
lldbUtility
|
||||
lldbHost
|
||||
lldbPluginPlatformMacOSX
|
||||
lldbPluginProtocolServerMCP
|
||||
lldbProtocolMCP
|
||||
lldbUtility
|
||||
LLVMTestingSupport
|
||||
)
|
||||
|
@ -6,14 +6,14 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "Plugins/Protocol/MCP/Protocol.h"
|
||||
#include "TestingSupport/TestUtilities.h"
|
||||
#include "lldb/Protocol/MCP/Protocol.h"
|
||||
#include "llvm/Testing/Support/Error.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
using namespace lldb;
|
||||
using namespace lldb_private;
|
||||
using namespace lldb_private::mcp::protocol;
|
||||
using namespace lldb_protocol::mcp;
|
||||
|
||||
TEST(ProtocolMCPTest, Request) {
|
||||
Request request;
|
||||
|
11
lldb/unittests/ProtocolServer/CMakeLists.txt
Normal file
11
lldb/unittests/ProtocolServer/CMakeLists.txt
Normal file
@ -0,0 +1,11 @@
|
||||
add_lldb_unittest(ProtocolServerTests
|
||||
ProtocolMCPServerTest.cpp
|
||||
|
||||
LINK_LIBS
|
||||
lldbCore
|
||||
lldbUtility
|
||||
lldbHost
|
||||
lldbPluginPlatformMacOSX
|
||||
lldbPluginProtocolServerMCP
|
||||
LLVMTestingSupport
|
||||
)
|
@ -16,13 +16,14 @@
|
||||
#include "lldb/Host/HostInfo.h"
|
||||
#include "lldb/Host/JSONTransport.h"
|
||||
#include "lldb/Host/Socket.h"
|
||||
#include "lldb/Protocol/MCP/Protocol.h"
|
||||
#include "llvm/Testing/Support/Error.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
using namespace llvm;
|
||||
using namespace lldb;
|
||||
using namespace lldb_private;
|
||||
using namespace lldb_private::mcp::protocol;
|
||||
using namespace lldb_protocol::mcp;
|
||||
|
||||
namespace {
|
||||
class TestProtocolServerMCP : public lldb_private::mcp::ProtocolServerMCP {
|
||||
@ -47,8 +48,7 @@ class TestTool : public mcp::Tool {
|
||||
public:
|
||||
using mcp::Tool::Tool;
|
||||
|
||||
virtual llvm::Expected<mcp::protocol::TextResult>
|
||||
Call(const ToolArguments &args) override {
|
||||
virtual llvm::Expected<TextResult> Call(const ToolArguments &args) override {
|
||||
std::string argument;
|
||||
if (const json::Object *args_obj =
|
||||
std::get<json::Value>(args).getAsObject()) {
|
||||
@ -57,8 +57,8 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
mcp::protocol::TextResult text_result;
|
||||
text_result.content.emplace_back(mcp::protocol::TextContent{{argument}});
|
||||
TextResult text_result;
|
||||
text_result.content.emplace_back(TextContent{{argument}});
|
||||
return text_result;
|
||||
}
|
||||
};
|
||||
@ -100,8 +100,7 @@ class ErrorTool : public mcp::Tool {
|
||||
public:
|
||||
using mcp::Tool::Tool;
|
||||
|
||||
virtual llvm::Expected<mcp::protocol::TextResult>
|
||||
Call(const ToolArguments &args) override {
|
||||
virtual llvm::Expected<TextResult> Call(const ToolArguments &args) override {
|
||||
return llvm::createStringError("error");
|
||||
}
|
||||
};
|
||||
@ -111,10 +110,9 @@ class FailTool : public mcp::Tool {
|
||||
public:
|
||||
using mcp::Tool::Tool;
|
||||
|
||||
virtual llvm::Expected<mcp::protocol::TextResult>
|
||||
Call(const ToolArguments &args) override {
|
||||
mcp::protocol::TextResult text_result;
|
||||
text_result.content.emplace_back(mcp::protocol::TextContent{{"failed"}});
|
||||
virtual llvm::Expected<TextResult> Call(const ToolArguments &args) override {
|
||||
TextResult text_result;
|
||||
text_result.content.emplace_back(TextContent{{"failed"}});
|
||||
text_result.isError = true;
|
||||
return text_result;
|
||||
}
|
||||
@ -309,8 +307,7 @@ TEST_F(ProtocolServerMCPTest, NotificationInitialized) {
|
||||
std::mutex mutex;
|
||||
|
||||
m_server_up->AddNotificationHandler(
|
||||
"notifications/initialized",
|
||||
[&](const mcp::protocol::Notification ¬ification) {
|
||||
"notifications/initialized", [&](const Notification ¬ification) {
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
handler_called = true;
|
Loading…
x
Reference in New Issue
Block a user