Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions lldb/include/lldb/Host/JSONTransport.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,8 @@ template <typename Req, typename Resp, typename Evt> class Transport {
virtual llvm::Expected<MainLoop::ReadHandleUP>
RegisterMessageHandler(MainLoop &loop, MessageHandler &handler) = 0;

protected:
// FIXME: Refactor mcp::Server to not directly access log on the transport.
// protected:
template <typename... Ts> inline auto Logv(const char *Fmt, Ts &&...Vals) {
Log(llvm::formatv(Fmt, std::forward<Ts>(Vals)...).str());
}
Expand Down Expand Up @@ -139,16 +140,18 @@ class JSONTransport : public Transport<Req, Resp, Evt> {
/// detail.
static constexpr size_t kReadBufferSize = 1024;

protected:
virtual llvm::Expected<std::vector<std::string>> Parse() = 0;
virtual std::string Encode(const llvm::json::Value &message) = 0;
// FIXME: Write should be protected.
llvm::Error Write(const llvm::json::Value &message) {
this->Logv("<-- {0}", message);
std::string output = Encode(message);
size_t bytes_written = output.size();
return m_out->Write(output.data(), bytes_written).takeError();
}

protected:
virtual llvm::Expected<std::vector<std::string>> Parse() = 0;
virtual std::string Encode(const llvm::json::Value &message) = 0;

llvm::SmallString<kReadBufferSize> m_buffer;

private:
Expand Down
28 changes: 6 additions & 22 deletions lldb/include/lldb/Protocol/MCP/Server.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,33 +14,17 @@
#include "lldb/Protocol/MCP/Protocol.h"
#include "lldb/Protocol/MCP/Resource.h"
#include "lldb/Protocol/MCP/Tool.h"
#include "lldb/Protocol/MCP/Transport.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/Support/Error.h"
#include <mutex>
#include "llvm/Support/JSON.h"
#include <functional>
#include <memory>
#include <string>
#include <vector>

namespace lldb_protocol::mcp {

class MCPTransport
: public lldb_private::JSONRPCTransport<Request, Response, Notification> {
public:
using LogCallback = std::function<void(llvm::StringRef message)>;

MCPTransport(lldb::IOObjectSP in, lldb::IOObjectSP out,
std::string client_name, LogCallback log_callback = {})
: JSONRPCTransport(in, out), m_client_name(std::move(client_name)),
m_log_callback(log_callback) {}
virtual ~MCPTransport() = default;

void Log(llvm::StringRef message) override {
if (m_log_callback)
m_log_callback(llvm::formatv("{0}: {1}", m_client_name, message).str());
}

private:
std::string m_client_name;
LogCallback m_log_callback;
};

/// Information about this instance of lldb's MCP server for lldb-mcp to use to
/// coordinate connecting an lldb-mcp client.
struct ServerInfo {
Expand Down
48 changes: 48 additions & 0 deletions lldb/include/lldb/Protocol/MCP/Transport.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
//===----------------------------------------------------------------------===//
//
// 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_TRANSPORT_H
#define LLDB_PROTOCOL_MCP_TRANSPORT_H

#include "lldb/Host/JSONTransport.h"
#include "lldb/Protocol/MCP/Protocol.h"
#include "lldb/lldb-forward.h"
#include "llvm/ADT/FunctionExtras.h"
#include "llvm/ADT/StringRef.h"

namespace lldb_protocol::mcp {

/// Generic transport that uses the MCP protocol.
using MCPTransport = lldb_private::Transport<Request, Response, Notification>;

/// Generic logging callback, to allow the MCP server / client / transport layer
/// to be independent of the lldb log implementation.
using LogCallback = llvm::unique_function<void(llvm::StringRef message)>;

class Transport final
: public lldb_private::JSONRPCTransport<Request, Response, Notification> {
public:
Transport(lldb::IOObjectSP in, lldb::IOObjectSP out,
LogCallback log_callback = {});
virtual ~Transport() = default;

/// Transport is not copyable.
/// @{
Transport(const Transport &) = delete;
void operator=(const Transport &) = delete;
/// @}

void Log(llvm::StringRef message) override;

private:
LogCallback m_log_callback;
};

} // namespace lldb_protocol::mcp

#endif
6 changes: 3 additions & 3 deletions lldb/source/Plugins/Protocol/MCP/ProtocolServerMCP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,9 @@ void ProtocolServerMCP::AcceptCallback(std::unique_ptr<Socket> socket) {
LLDB_LOG(log, "New MCP client connected: {0}", client_name);

lldb::IOObjectSP io_sp = std::move(socket);
auto transport_up = std::make_unique<lldb_protocol::mcp::MCPTransport>(
io_sp, io_sp, std::move(client_name), [&](llvm::StringRef message) {
LLDB_LOG(GetLog(LLDBLog::Host), "{0}", message);
auto transport_up = std::make_unique<lldb_protocol::mcp::Transport>(
io_sp, io_sp, [client_name](llvm::StringRef message) {
LLDB_LOG(GetLog(LLDBLog::Host), "{0}: {1}", client_name, message);
});
auto instance_up = std::make_unique<lldb_protocol::mcp::Server>(
std::string(kName), std::string(kVersion), std::move(transport_up),
Expand Down
1 change: 1 addition & 0 deletions lldb/source/Protocol/MCP/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ add_lldb_library(lldbProtocolMCP NO_PLUGIN_DEPENDENCIES
Protocol.cpp
Server.cpp
Tool.cpp
Transport.cpp

LINK_COMPONENTS
Support
Expand Down
23 changes: 23 additions & 0 deletions lldb/source/Protocol/MCP/Transport.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
//===----------------------------------------------------------------------===//
//
// 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/Transport.h"
#include "llvm/ADT/StringRef.h"
#include <utility>

using namespace lldb_protocol::mcp;
using namespace llvm;

Transport::Transport(lldb::IOObjectSP in, lldb::IOObjectSP out,
LogCallback log_callback)
: JSONRPCTransport(in, out), m_log_callback(std::move(log_callback)) {}

void Transport::Log(StringRef message) {
if (m_log_callback)
m_log_callback(message);
}
7 changes: 4 additions & 3 deletions lldb/tools/lldb-mcp/lldb-mcp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,10 @@ int main(int argc, char *argv[]) {
[](MainLoopBase &loop) { loop.RequestTermination(); });
});

auto transport_up = std::make_unique<lldb_protocol::mcp::MCPTransport>(
input, output, std::string(client_name),
[&](llvm::StringRef message) { llvm::errs() << message << '\n'; });
auto transport_up = std::make_unique<lldb_protocol::mcp::Transport>(
input, output, [&](llvm::StringRef message) {
llvm::errs() << formatv("{0}: {1}", client_name, message) << '\n';
});

auto instance_up = std::make_unique<lldb_protocol::mcp::Server>(
std::string(kName), std::string(kVersion), std::move(transport_up), loop);
Expand Down
20 changes: 4 additions & 16 deletions lldb/unittests/Protocol/ProtocolMCPServerTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "lldb/Protocol/MCP/Resource.h"
#include "lldb/Protocol/MCP/Server.h"
#include "lldb/Protocol/MCP/Tool.h"
#include "lldb/Protocol/MCP/Transport.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/JSON.h"
Expand All @@ -36,19 +37,6 @@ using namespace lldb_private;
using namespace lldb_protocol::mcp;

namespace {
class TestMCPTransport final : public MCPTransport {
public:
TestMCPTransport(lldb::IOObjectSP in, lldb::IOObjectSP out)
: lldb_protocol::mcp::MCPTransport(in, out, "unittest") {}

using MCPTransport::Write;

void Log(llvm::StringRef message) override {
log_messages.emplace_back(message);
}

std::vector<std::string> log_messages;
};

class TestServer : public Server {
public:
Expand Down Expand Up @@ -134,7 +122,7 @@ class ProtocolServerMCPTest : public PipePairTest {
public:
SubsystemRAII<FileSystem, HostInfo, Socket> subsystems;

std::unique_ptr<TestMCPTransport> transport_up;
std::unique_ptr<lldb_protocol::mcp::Transport> transport_up;
std::unique_ptr<TestServer> server_up;
MainLoop loop;
MockMessageHandler<Request, Response, Notification> message_handler;
Expand Down Expand Up @@ -163,7 +151,7 @@ class ProtocolServerMCPTest : public PipePairTest {
void SetUp() override {
PipePairTest::SetUp();

transport_up = std::make_unique<TestMCPTransport>(
transport_up = std::make_unique<lldb_protocol::mcp::Transport>(
std::make_shared<NativeFile>(input.GetReadFileDescriptor(),
File::eOpenOptionReadOnly,
NativeFile::Unowned),
Expand All @@ -173,7 +161,7 @@ class ProtocolServerMCPTest : public PipePairTest {

server_up = std::make_unique<TestServer>(
"lldb-mcp", "0.1.0",
std::make_unique<TestMCPTransport>(
std::make_unique<lldb_protocol::mcp::Transport>(
std::make_shared<NativeFile>(output.GetReadFileDescriptor(),
File::eOpenOptionReadOnly,
NativeFile::Unowned),
Expand Down
Loading