15#include "llvm/ADT/SmallString.h"
16#include "llvm/Support/FileSystem.h"
17#include "llvm/Support/JSON.h"
18#include "llvm/Support/Signals.h"
25 if (!m_filename.empty())
26 sys::RemoveFileOnSignal(m_filename);
32 *
this = std::move(other);
56 json::ObjectMapper O(V, P);
61 std::string buf = formatv(
"{0}",
toJSON(info)).str();
62 size_t num_bytes = buf.size();
64 FileSpec user_lldb_dir = HostInfo::GetUserLLDBDir();
68 return error.takeError();
71 formatv(
"lldb-mcp-{0}.json", getpid()).str());
76 Expected<lldb::FileUP> file =
79 return file.takeError();
80 if (llvm::Error
error = (*file)->Write(buf.data(), num_bytes).takeError())
86 namespace path = llvm::sys::path;
87 FileSpec user_lldb_dir = HostInfo::GetUserLLDBDir();
90 vfs::directory_iterator it = fs.
DirBegin(user_lldb_dir, EC);
91 vfs::directory_iterator end;
92 std::vector<ServerInfo> infos;
93 for (; it != end && !EC; it.increment(EC)) {
95 auto path = entry.path();
96 auto name = path::filename(path);
97 if (!name.starts_with(
"lldb-mcp-") || !name.ends_with(
".json"))
101 auto info = json::parse<ServerInfo>(toStringRef(buffer->GetData()));
103 return info.takeError();
105 infos.emplace_back(std::move(*info));
121 std::placeholders::_1));
123 std::placeholders::_1));
125 std::placeholders::_1));
127 this, std::placeholders::_1));
129 this, std::placeholders::_1));
135 llvm::Expected<Response> response = it->second(request);
138 response->id = request.
id;
142 return llvm::make_error<MCPError>(
143 llvm::formatv(
"no handler for request: {0}", request.
method).str());
149 it->second(notification);
157 m_tools[tool->GetName()] = std::move(tool);
161 std::unique_ptr<ResourceProvider> resource_provider) {
162 if (!resource_provider)
183 response.
result = std::move(result);
191 for (
const auto &tool :
m_tools)
192 result.
tools.emplace_back(tool.second->GetDefinition());
194 response.
result = std::move(result);
203 return llvm::createStringError(
"no tool parameters");
205 json::Path::Root root(
"params");
207 return root.getError();
209 llvm::StringRef tool_name = params.
name;
210 if (tool_name.empty())
211 return llvm::createStringError(
"no tool name");
213 auto it =
m_tools.find(tool_name);
215 return llvm::createStringError(llvm::formatv(
"no tool \"{0}\"", tool_name));
221 llvm::Expected<CallToolResult> text_result = it->second->Call(tool_args);
223 return text_result.takeError();
234 for (std::unique_ptr<ResourceProvider> &resource_provider_up :
236 for (
const Resource &resource : resource_provider_up->GetResources())
239 response.
result = std::move(result);
248 return llvm::createStringError(
"no resource parameters");
251 json::Path::Root root(
"params");
253 return root.getError();
255 llvm::StringRef uri_str = params.
uri;
257 return llvm::createStringError(
"no resource uri");
259 for (std::unique_ptr<ResourceProvider> &resource_provider_up :
261 llvm::Expected<ReadResourceResult> result =
262 resource_provider_up->ReadResource(uri_str);
264 llvm::consumeError(result.takeError());
268 return result.takeError();
271 response.
result = std::move(*result);
275 return make_error<MCPError>(
276 llvm::formatv(
"no resource handler for uri: {0}", uri_str).str(),
295 auto SendResponse = [
this](
const Response &response) {
297 Log(llvm::toString(std::move(
error)));
300 llvm::Expected<Response> response =
Handle(request);
302 return SendResponse(*response);
305 llvm::handleAllErrors(
306 response.takeError(),
307 [&](
const MCPError &err) { protocol_error = err.toProtocolError(); },
308 [&](
const llvm::ErrorInfoBase &err) {
309 protocol_error.code = MCPError::kInternalError;
310 protocol_error.message = err.message();
313 error_response.
id = request.
id;
314 error_response.
result = std::move(protocol_error);
315 SendResponse(error_response);
319 Log(
"unexpected MCP message: response");
327 Log(llvm::toString(std::move(
error)));
static llvm::raw_ostream & error(Stream &strm)
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.
ServerInfoHandle & operator=(ServerInfoHandle &&other) noexcept
ServerInfoHandle(llvm::StringRef filename="")
std::function< void(const Notification &)> NotificationHandler
llvm::Expected< Response > ToolsCallHandler(const Request &)
const std::string m_version
llvm::unique_function< void()> ClosedCallback
void AddTool(std::unique_ptr< Tool > tool)
void AddResourceProvider(std::unique_ptr< ResourceProvider > resource_provider)
llvm::StringMap< std::unique_ptr< Tool > > m_tools
std::vector< std::unique_ptr< ResourceProvider > > m_resource_providers
llvm::StringMap< NotificationHandler > m_notification_handlers
void AddRequestHandlers()
LogCallback m_log_callback
Server(std::string name, std::string version, MCPTransport &client, LogCallback log_callback={}, ClosedCallback closed_callback={})
llvm::StringMap< RequestHandler > m_request_handlers
ClosedCallback m_closed_callback
void OnError(llvm::Error) override
llvm::Expected< Response > ResourcesListHandler(const Request &)
llvm::Expected< Response > ResourcesReadHandler(const Request &)
llvm::Expected< Response > Handle(const Request &request)
llvm::Expected< Response > ToolsListHandler(const Request &)
void Log(llvm::StringRef)
void AddRequestHandler(llvm::StringRef method, RequestHandler handler)
std::function< llvm::Expected< Response >(const Request &)> RequestHandler
void Received(const Request &) override
ServerCapabilities GetCapabilities()
void AddNotificationHandler(llvm::StringRef method, NotificationHandler handler)
llvm::Expected< Response > InitializeHandler(const Request &)
A class that represents a running process on the host machine.
std::variant< std::monostate, llvm::json::Value > ToolArguments
llvm::json::Value toJSON(const Request &)
lldb_private::Transport< Request, Response, Notification > MCPTransport
Generic transport that uses the MCP protocol.
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
A notification which does not expect a response.
std::string method
The method to be invoked.
Sent from the client to the server, to read a specific resource URI.
std::string uri
The URI of the resource to read.
A request that expects a response.
std::optional< llvm::json::Value > params
The method's params.
std::string method
The method to be invoked.
A known resource that the server is capable of reading.
A response to a request, either an error or a result.
std::variant< Error, llvm::json::Value > result
The result of the request, either an Error or the JSON value of the response.
Capabilities that a server may support.
bool supportsResourcesList
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
static llvm::Expected< ServerInfoHandle > Write(const ServerInfo &)
Writes the server info into a unique file in ~/.lldb.