Skip to content

Commit 78f9910

Browse files
authored
Revert "[lldb] Adopt JSONTransport in the MCP Server (#155034)"
This reverts commit a49df8e.
1 parent 5dafe66 commit 78f9910

File tree

5 files changed

+127
-190
lines changed

5 files changed

+127
-190
lines changed

lldb/include/lldb/Protocol/MCP/Server.h

Lines changed: 7 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@
99
#ifndef LLDB_PROTOCOL_MCP_SERVER_H
1010
#define LLDB_PROTOCOL_MCP_SERVER_H
1111

12-
#include "lldb/Host/JSONTransport.h"
13-
#include "lldb/Host/MainLoop.h"
1412
#include "lldb/Protocol/MCP/Protocol.h"
1513
#include "lldb/Protocol/MCP/Resource.h"
1614
#include "lldb/Protocol/MCP/Tool.h"
@@ -20,52 +18,26 @@
2018

2119
namespace lldb_protocol::mcp {
2220

23-
class MCPTransport final
24-
: public lldb_private::JSONRPCTransport<Request, Response, Notification> {
21+
class Server {
2522
public:
26-
using LogCallback = std::function<void(llvm::StringRef message)>;
27-
28-
MCPTransport(lldb::IOObjectSP in, lldb::IOObjectSP out,
29-
std::string client_name, LogCallback log_callback = {})
30-
: JSONRPCTransport(in, out), m_client_name(std::move(client_name)),
31-
m_log_callback(log_callback) {}
32-
virtual ~MCPTransport() = default;
33-
34-
void Log(llvm::StringRef message) override {
35-
if (m_log_callback)
36-
m_log_callback(llvm::formatv("{0}: {1}", m_client_name, message).str());
37-
}
38-
39-
private:
40-
std::string m_client_name;
41-
LogCallback m_log_callback;
42-
};
43-
44-
class Server : public MCPTransport::MessageHandler {
45-
public:
46-
Server(std::string name, std::string version,
47-
std::unique_ptr<MCPTransport> transport_up,
48-
lldb_private::MainLoop &loop);
49-
~Server() = default;
50-
51-
using NotificationHandler = std::function<void(const Notification &)>;
23+
Server(std::string name, std::string version);
24+
virtual ~Server() = default;
5225

5326
void AddTool(std::unique_ptr<Tool> tool);
5427
void AddResourceProvider(std::unique_ptr<ResourceProvider> resource_provider);
55-
void AddNotificationHandler(llvm::StringRef method,
56-
NotificationHandler handler);
57-
58-
llvm::Error Run();
5928

6029
protected:
61-
Capabilities GetCapabilities();
30+
virtual Capabilities GetCapabilities() = 0;
6231

6332
using RequestHandler =
6433
std::function<llvm::Expected<Response>(const Request &)>;
34+
using NotificationHandler = std::function<void(const Notification &)>;
6535

6636
void AddRequestHandlers();
6737

6838
void AddRequestHandler(llvm::StringRef method, RequestHandler handler);
39+
void AddNotificationHandler(llvm::StringRef method,
40+
NotificationHandler handler);
6941

7042
llvm::Expected<std::optional<Message>> HandleData(llvm::StringRef data);
7143

@@ -80,23 +52,12 @@ class Server : public MCPTransport::MessageHandler {
8052
llvm::Expected<Response> ResourcesListHandler(const Request &);
8153
llvm::Expected<Response> ResourcesReadHandler(const Request &);
8254

83-
void Received(const Request &) override;
84-
void Received(const Response &) override;
85-
void Received(const Notification &) override;
86-
void OnError(llvm::Error) override;
87-
void OnClosed() override;
88-
89-
void TerminateLoop();
90-
9155
std::mutex m_mutex;
9256

9357
private:
9458
const std::string m_name;
9559
const std::string m_version;
9660

97-
std::unique_ptr<MCPTransport> m_transport_up;
98-
lldb_private::MainLoop &m_loop;
99-
10061
llvm::StringMap<std::unique_ptr<Tool>> m_tools;
10162
std::vector<std::unique_ptr<ResourceProvider>> m_resource_providers;
10263

lldb/source/Plugins/Protocol/MCP/ProtocolServerMCP.cpp

Lines changed: 78 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,24 @@ using namespace llvm;
2626

2727
LLDB_PLUGIN_DEFINE(ProtocolServerMCP)
2828

29+
static constexpr size_t kChunkSize = 1024;
2930
static constexpr llvm::StringLiteral kName = "lldb-mcp";
3031
static constexpr llvm::StringLiteral kVersion = "0.1.0";
3132

32-
ProtocolServerMCP::ProtocolServerMCP() : ProtocolServer() {}
33+
ProtocolServerMCP::ProtocolServerMCP()
34+
: ProtocolServer(),
35+
lldb_protocol::mcp::Server(std::string(kName), std::string(kVersion)) {
36+
AddNotificationHandler("notifications/initialized",
37+
[](const lldb_protocol::mcp::Notification &) {
38+
LLDB_LOG(GetLog(LLDBLog::Host),
39+
"MCP initialization complete");
40+
});
41+
42+
AddTool(
43+
std::make_unique<CommandTool>("lldb_command", "Run an lldb command."));
44+
45+
AddResourceProvider(std::make_unique<DebuggerResourceProvider>());
46+
}
3347

3448
ProtocolServerMCP::~ProtocolServerMCP() { llvm::consumeError(Stop()); }
3549

@@ -50,37 +64,57 @@ llvm::StringRef ProtocolServerMCP::GetPluginDescriptionStatic() {
5064
return "MCP Server.";
5165
}
5266

53-
void ProtocolServerMCP::Extend(lldb_protocol::mcp::Server &server) const {
54-
server.AddNotificationHandler("notifications/initialized",
55-
[](const lldb_protocol::mcp::Notification &) {
56-
LLDB_LOG(GetLog(LLDBLog::Host),
57-
"MCP initialization complete");
58-
});
59-
server.AddTool(
60-
std::make_unique<CommandTool>("lldb_command", "Run an lldb command."));
61-
server.AddResourceProvider(std::make_unique<DebuggerResourceProvider>());
62-
}
63-
6467
void ProtocolServerMCP::AcceptCallback(std::unique_ptr<Socket> socket) {
65-
Log *log = GetLog(LLDBLog::Host);
66-
std::string client_name = llvm::formatv("client_{0}", m_instances.size() + 1);
67-
LLDB_LOG(log, "New MCP client connected: {0}", client_name);
68+
LLDB_LOG(GetLog(LLDBLog::Host), "New MCP client ({0}) connected",
69+
m_clients.size() + 1);
6870

6971
lldb::IOObjectSP io_sp = std::move(socket);
70-
auto transport_up = std::make_unique<lldb_protocol::mcp::MCPTransport>(
71-
io_sp, io_sp, std::move(client_name), [&](llvm::StringRef message) {
72-
LLDB_LOG(GetLog(LLDBLog::Host), "{0}", message);
73-
});
74-
auto instance_up = std::make_unique<lldb_protocol::mcp::Server>(
75-
std::string(kName), std::string(kVersion), std::move(transport_up),
76-
m_loop);
77-
Extend(*instance_up);
78-
llvm::Error error = instance_up->Run();
79-
if (error) {
80-
LLDB_LOG_ERROR(log, std::move(error), "Failed to run MCP server: {0}");
72+
auto client_up = std::make_unique<Client>();
73+
client_up->io_sp = io_sp;
74+
Client *client = client_up.get();
75+
76+
Status status;
77+
auto read_handle_up = m_loop.RegisterReadObject(
78+
io_sp,
79+
[this, client](MainLoopBase &loop) {
80+
if (llvm::Error error = ReadCallback(*client)) {
81+
LLDB_LOG_ERROR(GetLog(LLDBLog::Host), std::move(error), "{0}");
82+
client->read_handle_up.reset();
83+
}
84+
},
85+
status);
86+
if (status.Fail())
8187
return;
88+
89+
client_up->read_handle_up = std::move(read_handle_up);
90+
m_clients.emplace_back(std::move(client_up));
91+
}
92+
93+
llvm::Error ProtocolServerMCP::ReadCallback(Client &client) {
94+
char chunk[kChunkSize];
95+
size_t bytes_read = sizeof(chunk);
96+
if (Status status = client.io_sp->Read(chunk, bytes_read); status.Fail())
97+
return status.takeError();
98+
client.buffer.append(chunk, bytes_read);
99+
100+
for (std::string::size_type pos;
101+
(pos = client.buffer.find('\n')) != std::string::npos;) {
102+
llvm::Expected<std::optional<lldb_protocol::mcp::Message>> message =
103+
HandleData(StringRef(client.buffer.data(), pos));
104+
client.buffer = client.buffer.erase(0, pos + 1);
105+
if (!message)
106+
return message.takeError();
107+
108+
if (*message) {
109+
std::string Output;
110+
llvm::raw_string_ostream OS(Output);
111+
OS << llvm::formatv("{0}", toJSON(**message)) << '\n';
112+
size_t num_bytes = Output.size();
113+
return client.io_sp->Write(Output.data(), num_bytes).takeError();
114+
}
82115
}
83-
m_instances.push_back(std::move(instance_up));
116+
117+
return llvm::Error::success();
84118
}
85119

86120
llvm::Error ProtocolServerMCP::Start(ProtocolServer::Connection connection) {
@@ -124,11 +158,27 @@ llvm::Error ProtocolServerMCP::Stop() {
124158

125159
// Stop the main loop.
126160
m_loop.AddPendingCallback(
127-
[](lldb_private::MainLoopBase &loop) { loop.RequestTermination(); });
161+
[](MainLoopBase &loop) { loop.RequestTermination(); });
128162

129163
// Wait for the main loop to exit.
130164
if (m_loop_thread.joinable())
131165
m_loop_thread.join();
132166

167+
{
168+
std::lock_guard<std::mutex> guard(m_mutex);
169+
m_listener.reset();
170+
m_listen_handlers.clear();
171+
m_clients.clear();
172+
}
173+
133174
return llvm::Error::success();
134175
}
176+
177+
lldb_protocol::mcp::Capabilities ProtocolServerMCP::GetCapabilities() {
178+
lldb_protocol::mcp::Capabilities capabilities;
179+
capabilities.tools.listChanged = true;
180+
// FIXME: Support sending notifications when a debugger/target are
181+
// added/removed.
182+
capabilities.resources.listChanged = false;
183+
return capabilities;
184+
}

lldb/source/Plugins/Protocol/MCP/ProtocolServerMCP.h

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@
1818

1919
namespace lldb_private::mcp {
2020

21-
class ProtocolServerMCP : public ProtocolServer {
21+
class ProtocolServerMCP : public ProtocolServer,
22+
public lldb_protocol::mcp::Server {
2223
public:
2324
ProtocolServerMCP();
2425
virtual ~ProtocolServerMCP() override;
@@ -38,24 +39,26 @@ class ProtocolServerMCP : public ProtocolServer {
3839

3940
Socket *GetSocket() const override { return m_listener.get(); }
4041

41-
protected:
42-
// This adds tools and resource providers that
43-
// are specific to this server. Overridable by the unit tests.
44-
virtual void Extend(lldb_protocol::mcp::Server &server) const;
45-
4642
private:
4743
void AcceptCallback(std::unique_ptr<Socket> socket);
4844

45+
lldb_protocol::mcp::Capabilities GetCapabilities() override;
46+
4947
bool m_running = false;
5048

51-
lldb_private::MainLoop m_loop;
49+
MainLoop m_loop;
5250
std::thread m_loop_thread;
53-
std::mutex m_mutex;
5451

5552
std::unique_ptr<Socket> m_listener;
56-
5753
std::vector<MainLoopBase::ReadHandleUP> m_listen_handlers;
58-
std::vector<std::unique_ptr<lldb_protocol::mcp::Server>> m_instances;
54+
55+
struct Client {
56+
lldb::IOObjectSP io_sp;
57+
MainLoopBase::ReadHandleUP read_handle_up;
58+
std::string buffer;
59+
};
60+
llvm::Error ReadCallback(Client &client);
61+
std::vector<std::unique_ptr<Client>> m_clients;
5962
};
6063
} // namespace lldb_private::mcp
6164

lldb/source/Protocol/MCP/Server.cpp

Lines changed: 2 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,8 @@
1212
using namespace lldb_protocol::mcp;
1313
using namespace llvm;
1414

15-
Server::Server(std::string name, std::string version,
16-
std::unique_ptr<MCPTransport> transport_up,
17-
lldb_private::MainLoop &loop)
18-
: m_name(std::move(name)), m_version(std::move(version)),
19-
m_transport_up(std::move(transport_up)), m_loop(loop) {
15+
Server::Server(std::string name, std::string version)
16+
: m_name(std::move(name)), m_version(std::move(version)) {
2017
AddRequestHandlers();
2118
}
2219

@@ -235,71 +232,3 @@ llvm::Expected<Response> Server::ResourcesReadHandler(const Request &request) {
235232
llvm::formatv("no resource handler for uri: {0}", uri_str).str(),
236233
MCPError::kResourceNotFound);
237234
}
238-
239-
Capabilities Server::GetCapabilities() {
240-
lldb_protocol::mcp::Capabilities capabilities;
241-
capabilities.tools.listChanged = true;
242-
// FIXME: Support sending notifications when a debugger/target are
243-
// added/removed.
244-
capabilities.resources.listChanged = false;
245-
return capabilities;
246-
}
247-
248-
llvm::Error Server::Run() {
249-
auto handle = m_transport_up->RegisterMessageHandler(m_loop, *this);
250-
if (!handle)
251-
return handle.takeError();
252-
253-
lldb_private::Status status = m_loop.Run();
254-
if (status.Fail())
255-
return status.takeError();
256-
257-
return llvm::Error::success();
258-
}
259-
260-
void Server::Received(const Request &request) {
261-
auto SendResponse = [this](const Response &response) {
262-
if (llvm::Error error = m_transport_up->Send(response))
263-
m_transport_up->Log(llvm::toString(std::move(error)));
264-
};
265-
266-
llvm::Expected<Response> response = Handle(request);
267-
if (response)
268-
return SendResponse(*response);
269-
270-
lldb_protocol::mcp::Error protocol_error;
271-
llvm::handleAllErrors(
272-
response.takeError(),
273-
[&](const MCPError &err) { protocol_error = err.toProtocolError(); },
274-
[&](const llvm::ErrorInfoBase &err) {
275-
protocol_error.code = MCPError::kInternalError;
276-
protocol_error.message = err.message();
277-
});
278-
Response error_response;
279-
error_response.id = request.id;
280-
error_response.result = std::move(protocol_error);
281-
SendResponse(error_response);
282-
}
283-
284-
void Server::Received(const Response &response) {
285-
m_transport_up->Log("unexpected MCP message: response");
286-
}
287-
288-
void Server::Received(const Notification &notification) {
289-
Handle(notification);
290-
}
291-
292-
void Server::OnError(llvm::Error error) {
293-
m_transport_up->Log(llvm::toString(std::move(error)));
294-
TerminateLoop();
295-
}
296-
297-
void Server::OnClosed() {
298-
m_transport_up->Log("EOF");
299-
TerminateLoop();
300-
}
301-
302-
void Server::TerminateLoop() {
303-
m_loop.AddPendingCallback(
304-
[](lldb_private::MainLoopBase &loop) { loop.RequestTermination(); });
305-
}

0 commit comments

Comments
 (0)