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"
14#include "lldb/Host/HostInfo.h"
17#include "lldb/Utility/Log.h"
18#include "llvm/ADT/StringExtras.h"
19#include "llvm/Support/Error.h"
20#include "llvm/Support/Threading.h"
21#include <thread>
22
23using namespace lldb_private;
24using namespace lldb_private::mcp;
25using namespace lldb_protocol::mcp;
26using namespace llvm;
27
29
30static constexpr llvm::StringLiteral kName = "lldb-mcp";
31static constexpr llvm::StringLiteral kVersion = "0.1.0";
32
34
35ProtocolServerMCP::~ProtocolServerMCP() { llvm::consumeError(Stop()); }
36
41
47
49 return std::make_unique<ProtocolServerMCP>();
50}
51
53 return "MCP Server.";
54}
55
57 server.AddNotificationHandler("notifications/initialized",
60 "MCP initialization complete");
61 });
62 server.AddTool(
63 std::make_unique<CommandTool>("lldb_command", "Run an lldb command."));
64 server.AddResourceProvider(std::make_unique<DebuggerResourceProvider>());
65}
66
67void ProtocolServerMCP::AcceptCallback(std::unique_ptr<Socket> socket) {
68 Log *log = GetLog(LLDBLog::Host);
69 std::string client_name = llvm::formatv("client_{0}", m_instances.size() + 1);
70 LLDB_LOG(log, "New MCP client connected: {0}", client_name);
71
72 lldb::IOObjectSP io_sp = std::move(socket);
73 auto transport_up = std::make_unique<lldb_protocol::mcp::Transport>(
74 io_sp, io_sp, [client_name](llvm::StringRef message) {
75 LLDB_LOG(GetLog(LLDBLog::Host), "{0}: {1}", client_name, message);
76 });
77 auto instance_up = std::make_unique<lldb_protocol::mcp::Server>(
78 std::string(kName), std::string(kVersion), std::move(transport_up),
79 m_loop);
80 Extend(*instance_up);
81 llvm::Error error = instance_up->Run();
82 if (error) {
83 LLDB_LOG_ERROR(log, std::move(error), "Failed to run MCP server: {0}");
84 return;
85 }
86 m_instances.push_back(std::move(instance_up));
87}
88
90 std::lock_guard<std::mutex> guard(m_mutex);
91
92 if (m_running)
93 return llvm::createStringError("the MCP server is already running");
94
95 Status status;
96 m_listener = Socket::Create(connection.protocol, status);
97 if (status.Fail())
98 return status.takeError();
99
100 status = m_listener->Listen(connection.name, /*backlog=*/5);
101 if (status.Fail())
102 return status.takeError();
103
104 auto handles =
106 this, std::placeholders::_1));
107 if (llvm::Error error = handles.takeError())
108 return error;
109
110 auto listening_uris = m_listener->GetListeningConnectionURI();
111 if (listening_uris.empty())
112 return createStringError("failed to get listening connections");
113 std::string address =
114 llvm::join(m_listener->GetListeningConnectionURI(), ", ");
115
116 ServerInfo info{listening_uris[0]};
117 llvm::Expected<ServerInfoHandle> handle = ServerInfo::Write(info);
118 if (!handle)
119 return handle.takeError();
120
121 m_running = true;
122 m_server_info_handle = std::move(*handle);
123 m_listen_handlers = std::move(*handles);
124 m_loop_thread = std::thread([=] {
125 llvm::set_thread_name("protocol-server.mcp");
126 m_loop.Run();
127 });
128
129 return llvm::Error::success();
130}
131
133 {
134 std::lock_guard<std::mutex> guard(m_mutex);
135 if (!m_running)
136 return createStringError("the MCP sever is not running");
137 m_running = false;
138 }
139
140 // Stop the main loop.
141 m_loop.AddPendingCallback(
142 [](lldb_private::MainLoopBase &loop) { loop.RequestTermination(); });
143
144 // Wait for the main loop to exit.
145 if (m_loop_thread.joinable())
146 m_loop_thread.join();
147
148 m_listen_handlers.clear();
150 m_instances.clear();
151
152 return llvm::Error::success();
153}
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
virtual llvm::Error Start(ProtocolServer::Connection connection) override
std::vector< MainLoopBase::ReadHandleUP > m_listen_handlers
std::vector< std::unique_ptr< lldb_protocol::mcp::Server > > m_instances
static lldb::ProtocolServerUP CreateInstance()
virtual llvm::Error Stop() override
void AcceptCallback(std::unique_ptr< Socket > socket)
static llvm::StringRef GetPluginNameStatic()
lldb_protocol::mcp::ServerInfoHandle m_server_info_handle
static llvm::StringRef GetPluginDescriptionStatic()
A handle that tracks the server info on disk and cleans up the disk record once it is no longer refer...
Definition Server.h:109
void AddTool(std::unique_ptr< Tool > tool)
Definition Server.cpp:157
void AddResourceProvider(std::unique_ptr< ResourceProvider > resource_provider)
Definition Server.cpp:163
void AddNotificationHandler(llvm::StringRef method, NotificationHandler handler)
Definition Server.cpp:174
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
A notification which does not expect a response.
Definition Protocol.h:88
Information about this instance of lldb's MCP server for lldb-mcp to use to coordinate connecting an ...
Definition Server.h:96
static llvm::Expected< ServerInfoHandle > Write(const ServerInfo &)
Writes the server info into a unique file in ~/.lldb.
Definition Server.cpp:63