@@ -26,10 +26,24 @@ using namespace llvm;
2626
2727LLDB_PLUGIN_DEFINE (ProtocolServerMCP)
2828
29+ static constexpr  size_t kChunkSize = 1024;
2930static  constexpr  llvm::StringLiteral kName  = " lldb-mcp" 
3031static  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
3448ProtocolServerMCP::~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- 
6467void  ProtocolServerMCP::AcceptCallback (std::unique_ptr<Socket> socket) {
65-   Log *log = GetLog (LLDBLog::Host);
66-   std::string client_name = llvm::formatv (" client_{0}" size () + 1 );
67-   LLDB_LOG (log, " New MCP client connected: {0}" 
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}" 
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 ' 
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
86120llvm::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+ }
0 commit comments