Skip to content

Commit 831a505

Browse files
committed
[lldb] Adjust ProtocolServer connection defaults.
This adjusts the ProtocolServer command to default to create a new connection listening on `localhost:0` and adds a new `ServerMetadata` details to `~/.lldb/mcp/lldb-<pid>.json` to record information about the current MCP server. This can be consumed by the lldb-mcp binary to establish a connection from an LLM client.
1 parent 71a065e commit 831a505

File tree

5 files changed

+76
-11
lines changed

5 files changed

+76
-11
lines changed

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,23 @@
1414
#include "lldb/Protocol/MCP/Resource.h"
1515
#include "lldb/Protocol/MCP/Tool.h"
1616
#include "lldb/Protocol/MCP/Transport.h"
17+
#include "lldb/lldb-types.h"
1718
#include "llvm/ADT/StringMap.h"
1819
#include "llvm/Support/Error.h"
20+
#include "llvm/Support/JSON.h"
1921

2022
namespace lldb_protocol::mcp {
2123

24+
/// Metadata about this instance of lldb's MCP server for lldb-mcp to use to
25+
/// coordinate connecting an lldb-mcp client.
26+
struct ServerMetadata {
27+
std::string connection_uri;
28+
lldb::pid_t pid;
29+
};
30+
llvm::json::Value toJSON(const ServerMetadata &SM);
31+
bool fromJSON(const llvm::json::Value &V, ServerMetadata &SM,
32+
llvm::json::Path P);
33+
2234
class Server : public Transport::MessageHandler {
2335
public:
2436
Server(std::string name, std::string version,

lldb/source/Commands/CommandObjectProtocolServer.cpp

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "lldb/Utility/UriParser.h"
1616
#include "llvm/ADT/STLExtras.h"
1717
#include "llvm/Support/FormatAdapters.h"
18+
#include <string>
1819

1920
using namespace llvm;
2021
using namespace lldb;
@@ -28,7 +29,7 @@ class CommandObjectProtocolServerStart : public CommandObjectParsed {
2829
CommandObjectProtocolServerStart(CommandInterpreter &interpreter)
2930
: CommandObjectParsed(interpreter, "protocol-server start",
3031
"start protocol server",
31-
"protocol-server start <protocol> <connection>") {
32+
"protocol-server start <protocol> [<connection>]") {
3233
AddSimpleArgumentList(lldb::eArgTypeProtocol, eArgRepeatPlain);
3334
AddSimpleArgumentList(lldb::eArgTypeConnectURL, eArgRepeatPlain);
3435
}
@@ -51,15 +52,13 @@ class CommandObjectProtocolServerStart : public CommandObjectParsed {
5152
return;
5253
}
5354

54-
if (args.GetArgumentCount() < 2) {
55-
result.AppendError("no connection specified");
56-
return;
57-
}
58-
llvm::StringRef connection_uri = args.GetArgumentAtIndex(1);
55+
std::string connection_uri = "listen://[localhost]:0";
56+
if (args.GetArgumentCount() > 2)
57+
connection_uri = args.GetArgumentAtIndex(1);
5958

6059
const char *connection_error =
61-
"unsupported connection specifier, expected 'accept:///path' or "
62-
"'listen://[host]:port', got '{0}'.";
60+
"unsupported connection specifier, expected 'accept:///path' "
61+
"or 'listen://[host]:port', got '{0}'.";
6362
auto uri = lldb_private::URI::Parse(connection_uri);
6463
if (!uri) {
6564
result.AppendErrorWithFormatv(connection_error, connection_uri);

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

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,14 @@
1010
#include "Resource.h"
1111
#include "Tool.h"
1212
#include "lldb/Core/PluginManager.h"
13-
#include "lldb/Protocol/MCP/MCPError.h"
14-
#include "lldb/Protocol/MCP/Tool.h"
13+
#include "lldb/Host/FileSystem.h"
14+
#include "lldb/Protocol/MCP/Server.h"
1515
#include "lldb/Utility/LLDBLog.h"
1616
#include "lldb/Utility/Log.h"
1717
#include "llvm/ADT/StringExtras.h"
18+
#include "llvm/Support/Error.h"
1819
#include "llvm/Support/Threading.h"
1920
#include <thread>
20-
#include <variant>
2121

2222
using namespace lldb_private;
2323
using namespace lldb_private::mcp;
@@ -104,6 +104,43 @@ llvm::Error ProtocolServerMCP::Start(ProtocolServer::Connection connection) {
104104
if (llvm::Error error = handles.takeError())
105105
return error;
106106

107+
auto listening_uris = m_listener->GetListeningConnectionURI();
108+
if (listening_uris.empty())
109+
return createStringError("Failed to list listening connections");
110+
std::string address =
111+
llvm::join(m_listener->GetListeningConnectionURI(), ", ");
112+
113+
llvm::SmallString<128> user_home_dir;
114+
FileSystem::Instance().GetHomeDirectory(user_home_dir);
115+
FileSpec mcp_registry_dir = FileSpec(user_home_dir.c_str());
116+
mcp_registry_dir.AppendPathComponent(".lldb");
117+
mcp_registry_dir.AppendPathComponent("mcp");
118+
119+
Status error(llvm::sys::fs::create_directory(mcp_registry_dir.GetPath()));
120+
if (error.Fail())
121+
return error.takeError();
122+
123+
m_mcp_registry_entry_path = mcp_registry_dir.CopyByAppendingPathComponent(
124+
formatv("lldb-{0}.json", getpid()).str());
125+
126+
const File::OpenOptions flags = File::eOpenOptionWriteOnly |
127+
File::eOpenOptionCanCreate |
128+
File::eOpenOptionTruncate;
129+
llvm::Expected<lldb::FileUP> file =
130+
FileSystem::Instance().Open(m_mcp_registry_entry_path, flags,
131+
lldb::eFilePermissionsFileDefault, false);
132+
if (!file)
133+
return file.takeError();
134+
135+
ServerMetadata metadata;
136+
metadata.connection_uri = listening_uris[0];
137+
metadata.pid = getpid();
138+
139+
std::string buf = formatv("{0}", toJSON(metadata)).str();
140+
size_t num_bytes = buf.size();
141+
if (llvm::Error error = (*file)->Write(buf.data(), num_bytes).takeError())
142+
return error;
143+
107144
m_running = true;
108145
m_listen_handlers = std::move(*handles);
109146
m_loop_thread = std::thread([=] {
@@ -122,6 +159,10 @@ llvm::Error ProtocolServerMCP::Stop() {
122159
m_running = false;
123160
}
124161

162+
if (!m_mcp_registry_entry_path.GetPath().empty())
163+
FileSystem::Instance().RemoveFile(m_mcp_registry_entry_path);
164+
m_mcp_registry_entry_path.Clear();
165+
125166
// Stop the main loop.
126167
m_loop.AddPendingCallback(
127168
[](lldb_private::MainLoopBase &loop) { loop.RequestTermination(); });

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ class ProtocolServerMCP : public ProtocolServer {
4848

4949
bool m_running = false;
5050

51+
FileSpec m_mcp_registry_entry_path;
5152
lldb_private::MainLoop m_loop;
5253
std::thread m_loop_thread;
5354
std::mutex m_mutex;

lldb/source/Protocol/MCP/Server.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,18 @@
1414
using namespace lldb_protocol::mcp;
1515
using namespace llvm;
1616

17+
llvm::json::Value toJSON(const ServerMetadata &SM) {
18+
return llvm::json::Object{{"connection_uri", SM.connection_uri},
19+
{"pid", SM.pid}};
20+
}
21+
22+
bool fromJSON(const llvm::json::Value &V, ServerMetadata &SM,
23+
llvm::json::Path P) {
24+
llvm::json::ObjectMapper O(V, P);
25+
return O && O.map("connection_uri", SM.connection_uri) &&
26+
O.map("pid", SM.pid);
27+
}
28+
1729
Server::Server(std::string name, std::string version,
1830
std::unique_ptr<Transport> transport_up,
1931
lldb_private::MainLoop &loop)

0 commit comments

Comments
 (0)