16#include "llvm/ADT/SmallString.h"
17#include "llvm/Support/ErrorExtras.h"
18#include "llvm/Support/FileSystem.h"
19#include "llvm/Support/JSON.h"
20#include "llvm/Support/Signals.h"
27 if (!m_filename.empty())
28 sys::RemoveFileOnSignal(m_filename);
34 *
this = std::move(other);
58 json::ObjectMapper O(V, P);
60 O.mapOptional(
"pid", SM.
pid);
66 formatv(
"lldb-mcp-{0}.json", pid).str());
73 stamped.
pid = getpid();
75 std::string buf = formatv(
"{0}",
toJSON(stamped)).str();
76 size_t num_bytes = buf.size();
78 FileSpec user_lldb_dir = HostInfo::GetUserLLDBDir();
82 return error.takeError();
89 Expected<lldb::FileUP> file =
92 return file.takeError();
93 if (llvm::Error
error = (*file)->Write(buf.data(), num_bytes).takeError())
102 if (std::error_code ec = sys::fs::remove(path))
103 return errorCodeToError(ec);
104 return llvm::Error::success();
108 namespace path = llvm::sys::path;
109 FileSpec user_lldb_dir = HostInfo::GetUserLLDBDir();
112 vfs::directory_iterator it = fs.
DirBegin(user_lldb_dir, EC);
113 vfs::directory_iterator end;
114 std::vector<ServerInfo> infos;
115 for (; it != end && !EC; it.increment(EC)) {
117 auto path = entry.path();
118 auto name = path::filename(path);
119 if (!name.starts_with(
"lldb-mcp-") || !name.ends_with(
".json"))
123 auto info = json::parse<ServerInfo>(toStringRef(buffer->GetData()));
125 return info.takeError();
127 infos.emplace_back(std::move(*info));
140 m_tools[tool->GetName()] = std::move(tool);
144 std::unique_ptr<ResourceProvider> resource_provider) {
145 if (!resource_provider)
162 binder_up->Bind<
void>(
"notifications/initialized",
163 [
this]() {
Log(
"MCP initialization complete"); });
170 binder->OnDisconnect([
this, transport_ptr]() {
172 "Client not found in m_instances");
175 binder->OnError([
this](llvm::Error err) {
176 Logv(
"Transport error: {0}", llvm::toString(std::move(err)));
179 if (llvm::Error err =
transport->RegisterMessageHandler(*binder))
183 return llvm::Error::success();
186Expected<InitializeResult>
198 for (
const auto &tool :
m_tools)
199 result.
tools.emplace_back(tool.second->GetDefinition());
204llvm::Expected<CallToolResult>
206 llvm::StringRef tool_name = params.
name;
207 if (tool_name.empty())
208 return llvm::createStringError(
"no tool name");
210 auto it =
m_tools.find(tool_name);
212 return llvm::createStringErrorV(
"no tool \"{0}\"", tool_name);
218 llvm::Expected<CallToolResult> text_result = it->second->Call(tool_args);
220 return text_result.takeError();
227 for (std::unique_ptr<ResourceProvider> &resource_provider_up :
229 for (
const Resource &resource : resource_provider_up->GetResources())
235Expected<ReadResourceResult>
237 StringRef uri_str = params.
uri;
239 return createStringError(
"no resource uri");
241 for (std::unique_ptr<ResourceProvider> &resource_provider_up :
243 Expected<ReadResourceResult> result =
244 resource_provider_up->ReadResource(uri_str);
246 consumeError(result.takeError());
250 return result.takeError();
255 return make_error<MCPError>(
256 formatv(
"no resource handler for uri: {0}", uri_str).str(),
static llvm::raw_ostream & error(Stream &strm)
static FileSpec GetServerInfoPath(lldb::pid_t pid)
Returns the on-disk registry path for the instance with the given pid.
FileSpec CopyByAppendingPathComponent(llvm::StringRef component) const
size_t GetPath(char *path, size_t max_path_length, bool denormalize=true) const
Extract the full path to the file.
int Open(const char *path, int flags, int mode=0600)
Wraps open in a platform-independent way.
llvm::vfs::directory_iterator DirBegin(const FileSpec &file_spec, std::error_code &ec)
Get a directory iterator.
static FileSystem & Instance()
std::shared_ptr< DataBuffer > CreateDataBuffer(const llvm::Twine &path, uint64_t size=0, uint64_t offset=0)
Create memory buffer from path.
static constexpr int64_t kResourceNotFound
A handle that tracks the server info on disk and cleans up the disk record once it is no longer refer...
llvm::SmallString< 128 > m_filename
void Remove()
Remove the file on disk, if one is tracked.
ServerInfoHandle & operator=(ServerInfoHandle &&other) noexcept
ServerInfoHandle(llvm::StringRef filename="")
const std::string m_version
void AddTool(std::unique_ptr< Tool > tool)
void AddResourceProvider(std::unique_ptr< ResourceProvider > resource_provider)
llvm::StringMap< std::unique_ptr< Tool > > m_tools
MCPBinderUP Bind(MCPTransport &)
std::vector< std::unique_ptr< ResourceProvider > > m_resource_providers
llvm::Expected< ReadResourceResult > ResourcesReadHandler(const ReadResourceParams &)
llvm::Error Accept(MCPTransportUP)
LogCallback m_log_callback
Server(std::string name, std::string version, LogCallback log_callback={})
llvm::Expected< ListToolsResult > ToolsListHandler()
void Log(llvm::StringRef message)
llvm::Expected< InitializeResult > InitializeHandler(const InitializeParams &)
llvm::Expected< CallToolResult > ToolsCallHandler(const CallToolParams &)
std::unique_ptr< lldb_protocol::mcp::MCPTransport > MCPTransportUP
llvm::Expected< ListResourcesResult > ResourcesListHandler()
auto Logv(const char *Fmt, Ts &&...Vals)
std::map< MCPTransport *, Client > m_instances
ServerCapabilities GetCapabilities()
A class that represents a running process on the host machine.
std::unique_ptr< MCPBinder > MCPBinderUP
std::variant< std::monostate, llvm::json::Value > ToolArguments
lldb_private::transport::JSONTransport< ProtocolDescriptor > MCPTransport
Generic transport that uses the MCP protocol.
llvm::json::Value toJSON(const Request &)
llvm::unique_function< void(llvm::StringRef message)> LogCallback
Generic logging callback, to allow the MCP server / client / transport layer to be independent of the...
static llvm::StringLiteral kProtocolVersion
bool fromJSON(const llvm::json::Value &, Request &, llvm::json::Path)
std::string name
Intended for programmatic or logical use, but used as a display name in past specs or fallback (if ti...
After receiving an initialize request from the client, the server sends this response.
std::string protocolVersion
The version of the Model Context Protocol that the server wants to use.
ServerCapabilities capabilities
Implementation serverInfo
The server’s response to a resources/list request from the client.
std::vector< Resource > resources
Sent from the client to the server, to read a specific resource URI.
std::string uri
The URI of the resource to read.
The server's response to a resources/read request from the client.
A known resource that the server is capable of reading.
Capabilities that a server may support.
bool supportsResourcesList
bool supportsResourcesSubscribe
Information about this instance of lldb's MCP server for lldb-mcp to use to coordinate connecting an ...
static llvm::Expected< std::vector< ServerInfo > > Load()
Loads any server info saved in ~/.lldb.
std::string connection_uri
lldb::pid_t pid
Process id of the lldb instance hosting this server, used as its stable identity.
static llvm::Error Remove(lldb::pid_t pid)
Removes the registry entry for the instance with the given pid.
static llvm::Expected< ServerInfoHandle > Write(const ServerInfo &)
Writes the server info into a unique file in ~/.lldb.