LLDB mainline
ProtocolServerMCP.cpp
Go to the documentation of this file.
1//===- ProtocolServerMCP.cpp ----------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "ProtocolServerMCP.h"
10#include "Resource.h"
11#include "Tool.h"
15#include "lldb/Utility/Log.h"
16#include "llvm/ADT/StringExtras.h"
17#include "llvm/Support/Error.h"
18#include "llvm/Support/Threading.h"
19#include <thread>
20
21using namespace lldb_private;
22using namespace lldb_private::mcp;
23using namespace lldb_protocol::mcp;
24using namespace llvm;
25
27
28static constexpr llvm::StringLiteral kName = "lldb-mcp";
29static constexpr llvm::StringLiteral kVersion = "0.1.0";
30
32
33ProtocolServerMCP::~ProtocolServerMCP() { llvm::consumeError(Stop()); }
34
39
45
47 return std::make_unique<ProtocolServerMCP>();
48}
49
51 return "MCP Server.";
52}
53
55 server.AddTool(
56 std::make_unique<CommandTool>("command", "Run an lldb command."));
57 server.AddTool(std::make_unique<DebuggerListTool>(
58 "debugger_list", "List debugger instances with their debugger_id."));
59 server.AddResourceProvider(std::make_unique<DebuggerResourceProvider>());
60}
61
62void ProtocolServerMCP::AcceptCallback(std::unique_ptr<Socket> socket) {
63 Log *log = GetLog(LLDBLog::Host);
64 std::string client_name = llvm::formatv("client_{0}", ++m_client_count);
65 LLDB_LOG(log, "New MCP client connected: {0}", client_name);
66
67 lldb::IOObjectSP io_sp = std::move(socket);
68 auto transport_up = std::make_unique<lldb_protocol::mcp::Transport>(
69 io_sp, io_sp, [client_name](llvm::StringRef message) {
70 LLDB_LOG(GetLog(LLDBLog::Host), "{0}: {1}", client_name, message);
71 });
72
73 if (auto error = m_server->Accept(m_loop, std::move(transport_up)))
74 LLDB_LOG_ERROR(log, std::move(error), "{0}:");
75}
76
78 std::lock_guard<std::mutex> guard(m_mutex);
79
80 if (m_running)
81 return llvm::createStringError("the MCP server is already running");
82
83 Status status;
84 m_listener = Socket::Create(connection.protocol, status);
85 if (status.Fail())
86 return status.takeError();
87
88 status = m_listener->Listen(connection.name, /*backlog=*/5);
89 if (status.Fail())
90 return status.takeError();
91
92 auto handles =
94 this, std::placeholders::_1));
95 if (llvm::Error error = handles.takeError())
96 return error;
97
98 auto listening_uris = m_listener->GetListeningConnectionURI();
99 if (listening_uris.empty())
100 return createStringError("failed to get listening connections");
101 std::string address =
102 llvm::join(m_listener->GetListeningConnectionURI(), ", ");
103
104 ServerInfo info{listening_uris[0]};
105 llvm::Expected<ServerInfoHandle> server_info_handle = ServerInfo::Write(info);
106 if (!server_info_handle)
107 return server_info_handle.takeError();
108
109 m_client_count = 0;
110 m_server = std::make_unique<lldb_protocol::mcp::Server>(
111 std::string(kName), std::string(kVersion), [](StringRef message) {
112 LLDB_LOG(GetLog(LLDBLog::Host), "MCP Server: {0}", message);
113 });
115
116 m_running = true;
117 m_server_info_handle = std::move(*server_info_handle);
118 m_accept_handles = std::move(*handles);
119 m_loop_thread = std::thread([this] {
120 llvm::set_thread_name("protocol-server.mcp");
121 m_loop.Run();
122 });
123
124 return llvm::Error::success();
125}
126
128 {
129 std::lock_guard<std::mutex> guard(m_mutex);
130 if (!m_running)
131 return createStringError("the MCP sever is not running");
132 m_running = false;
133 }
134
135 // Stop the main loop.
136 m_loop.AddPendingCallback(
137 [](lldb_private::MainLoopBase &loop) { loop.RequestTermination(); });
138
139 // Wait for the main loop to exit.
140 if (m_loop_thread.joinable())
141 m_loop_thread.join();
142
143 m_accept_handles.clear();
144
145 m_server.reset(nullptr);
146 m_server_info_handle.Remove();
147 m_listener.reset();
148
149 return llvm::Error::success();
150}
static llvm::raw_ostream & error(Stream &strm)
#define LLDB_LOG(log,...)
The LLDB_LOG* macros defined below are the way to emit log messages.
Definition Log.h:369
#define LLDB_LOG_ERROR(log, error,...)
Definition Log.h:392
#define LLDB_PLUGIN_DEFINE(PluginName)
static constexpr llvm::StringLiteral kName
static constexpr llvm::StringLiteral kVersion
static llvm::Error createStringError(const char *format, Args &&...args)
Definition Resource.cpp:59
virtual void RequestTermination()
static bool RegisterPlugin(llvm::StringRef name, llvm::StringRef description, ABICreateInstance create_callback)
static bool UnregisterPlugin(ABICreateInstance create_callback)
static llvm::Error Terminate()
static std::unique_ptr< Socket > Create(const SocketProtocol protocol, Status &error)
Definition Socket.cpp:200
An error handling class.
Definition Status.h:118
llvm::Error takeError()
Definition Status.h:170
bool Fail() const
Test for error condition.
Definition Status.cpp:294
std::unique_ptr< Socket > m_listener
virtual void Extend(lldb_protocol::mcp::Server &server) const
llvm::Error Start(ProtocolServer::Connection connection) override
std::vector< ReadHandleUP > m_accept_handles
static lldb::ProtocolServerUP CreateInstance()
void AcceptCallback(std::unique_ptr< Socket > socket)
static llvm::StringRef GetPluginNameStatic()
lldb_protocol::mcp::ServerInfoHandle m_server_info_handle
static llvm::StringRef GetPluginDescriptionStatic()
void AddTool(std::unique_ptr< Tool > tool)
Definition Server.cpp:116
void AddResourceProvider(std::unique_ptr< ResourceProvider > resource_provider)
Definition Server.cpp:122
A class that represents a running process on the host machine.
Log * GetLog(Cat mask)
Retrieve the Log object for the channel associated with the given log enum.
Definition Log.h:332
std::shared_ptr< lldb_private::IOObject > IOObjectSP
std::unique_ptr< lldb_private::ProtocolServer > ProtocolServerUP
Information about this instance of lldb's MCP server for lldb-mcp to use to coordinate connecting an ...
Definition Server.h:87
static llvm::Expected< ServerInfoHandle > Write(const ServerInfo &)
Writes the server info into a unique file in ~/.lldb.
Definition Server.cpp:61