LLDB mainline
Server.cpp
Go to the documentation of this file.
1//===----------------------------------------------------------------------===//
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
12#include "llvm/Support/JSON.h"
13
14using namespace lldb_protocol::mcp;
15using namespace llvm;
16
17llvm::json::Value lldb_protocol::mcp::toJSON(const ServerInfo &SM) {
18 return llvm::json::Object{{"connection_uri", SM.connection_uri},
19 {"pid", SM.pid}};
20}
21
22bool lldb_protocol::mcp::fromJSON(const llvm::json::Value &V, ServerInfo &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
29Server::Server(std::string name, std::string version,
30 std::unique_ptr<MCPTransport> transport_up,
32 : m_name(std::move(name)), m_version(std::move(version)),
33 m_transport_up(std::move(transport_up)), m_loop(loop) {
35}
36
38 AddRequestHandler("initialize", std::bind(&Server::InitializeHandler, this,
39 std::placeholders::_1));
40 AddRequestHandler("tools/list", std::bind(&Server::ToolsListHandler, this,
41 std::placeholders::_1));
42 AddRequestHandler("tools/call", std::bind(&Server::ToolsCallHandler, this,
43 std::placeholders::_1));
44 AddRequestHandler("resources/list", std::bind(&Server::ResourcesListHandler,
45 this, std::placeholders::_1));
46 AddRequestHandler("resources/read", std::bind(&Server::ResourcesReadHandler,
47 this, std::placeholders::_1));
48}
49
50llvm::Expected<Response> Server::Handle(const Request &request) {
51 auto it = m_request_handlers.find(request.method);
52 if (it != m_request_handlers.end()) {
53 llvm::Expected<Response> response = it->second(request);
54 if (!response)
55 return response;
56 response->id = request.id;
57 return *response;
58 }
59
60 return llvm::make_error<MCPError>(
61 llvm::formatv("no handler for request: {0}", request.method).str());
62}
63
64void Server::Handle(const Notification &notification) {
65 auto it = m_notification_handlers.find(notification.method);
66 if (it != m_notification_handlers.end()) {
67 it->second(notification);
68 return;
69 }
70}
71
72void Server::AddTool(std::unique_ptr<Tool> tool) {
73 if (!tool)
74 return;
75 m_tools[tool->GetName()] = std::move(tool);
76}
77
79 std::unique_ptr<ResourceProvider> resource_provider) {
80 if (!resource_provider)
81 return;
82 m_resource_providers.push_back(std::move(resource_provider));
83}
84
85void Server::AddRequestHandler(llvm::StringRef method, RequestHandler handler) {
86 m_request_handlers[method] = std::move(handler);
87}
88
89void Server::AddNotificationHandler(llvm::StringRef method,
90 NotificationHandler handler) {
91 m_notification_handlers[method] = std::move(handler);
92}
93
94llvm::Expected<Response> Server::InitializeHandler(const Request &request) {
95 Response response;
96 InitializeResult result;
99 result.serverInfo.name = m_name;
101 response.result = std::move(result);
102 return response;
103}
104
105llvm::Expected<Response> Server::ToolsListHandler(const Request &request) {
106 Response response;
107
108 ListToolsResult result;
109 for (const auto &tool : m_tools)
110 result.tools.emplace_back(tool.second->GetDefinition());
111
112 response.result = std::move(result);
113
114 return response;
115}
116
117llvm::Expected<Response> Server::ToolsCallHandler(const Request &request) {
118 Response response;
119
120 if (!request.params)
121 return llvm::createStringError("no tool parameters");
122 CallToolParams params;
123 json::Path::Root root("params");
124 if (!fromJSON(request.params, params, root))
125 return root.getError();
126
127 llvm::StringRef tool_name = params.name;
128 if (tool_name.empty())
129 return llvm::createStringError("no tool name");
130
131 auto it = m_tools.find(tool_name);
132 if (it == m_tools.end())
133 return llvm::createStringError(llvm::formatv("no tool \"{0}\"", tool_name));
134
135 ToolArguments tool_args;
136 if (params.arguments)
137 tool_args = *params.arguments;
138
139 llvm::Expected<CallToolResult> text_result = it->second->Call(tool_args);
140 if (!text_result)
141 return text_result.takeError();
142
143 response.result = toJSON(*text_result);
144
145 return response;
146}
147
148llvm::Expected<Response> Server::ResourcesListHandler(const Request &request) {
149 Response response;
150
151 ListResourcesResult result;
152 for (std::unique_ptr<ResourceProvider> &resource_provider_up :
154 for (const Resource &resource : resource_provider_up->GetResources())
155 result.resources.push_back(resource);
156
157 response.result = std::move(result);
158
159 return response;
160}
161
162llvm::Expected<Response> Server::ResourcesReadHandler(const Request &request) {
163 Response response;
164
165 if (!request.params)
166 return llvm::createStringError("no resource parameters");
167
168 ReadResourceParams params;
169 json::Path::Root root("params");
170 if (!fromJSON(request.params, params, root))
171 return root.getError();
172
173 llvm::StringRef uri_str = params.uri;
174 if (uri_str.empty())
175 return llvm::createStringError("no resource uri");
176
177 for (std::unique_ptr<ResourceProvider> &resource_provider_up :
179 llvm::Expected<ReadResourceResult> result =
180 resource_provider_up->ReadResource(uri_str);
181 if (result.errorIsA<UnsupportedURI>()) {
182 llvm::consumeError(result.takeError());
183 continue;
184 }
185 if (!result)
186 return result.takeError();
187
188 Response response;
189 response.result = std::move(*result);
190 return response;
191 }
192
193 return make_error<MCPError>(
194 llvm::formatv("no resource handler for uri: {0}", uri_str).str(),
196}
197
200 capabilities.supportsToolsList = true;
201 // FIXME: Support sending notifications when a debugger/target are
202 // added/removed.
203 capabilities.supportsResourcesList = false;
204 return capabilities;
205}
206
207llvm::Error Server::Run() {
208 auto handle = m_transport_up->RegisterMessageHandler(m_loop, *this);
209 if (!handle)
210 return handle.takeError();
211
213 if (status.Fail())
214 return status.takeError();
215
216 return llvm::Error::success();
217}
218
219void Server::Received(const Request &request) {
220 auto SendResponse = [this](const Response &response) {
221 if (llvm::Error error = m_transport_up->Send(response))
222 m_transport_up->Log(llvm::toString(std::move(error)));
223 };
224
225 llvm::Expected<Response> response = Handle(request);
226 if (response)
227 return SendResponse(*response);
228
229 lldb_protocol::mcp::Error protocol_error;
230 llvm::handleAllErrors(
231 response.takeError(),
232 [&](const MCPError &err) { protocol_error = err.toProtocolError(); },
233 [&](const llvm::ErrorInfoBase &err) {
234 protocol_error.code = MCPError::kInternalError;
235 protocol_error.message = err.message();
236 });
237 Response error_response;
238 error_response.id = request.id;
239 error_response.result = std::move(protocol_error);
240 SendResponse(error_response);
241}
242
243void Server::Received(const Response &response) {
244 m_transport_up->Log("unexpected MCP message: response");
245}
246
247void Server::Received(const Notification &notification) {
248 Handle(notification);
249}
250
251void Server::OnError(llvm::Error error) {
252 m_transport_up->Log(llvm::toString(std::move(error)));
254}
255
257 m_transport_up->Log("EOF");
259}
260
263 [](lldb_private::MainLoopBase &loop) { loop.RequestTermination(); });
264}
static llvm::raw_ostream & error(Stream &strm)
void AddPendingCallback(const Callback &callback)
Definition: MainLoopBase.h:60
virtual void RequestTermination()
Definition: MainLoopBase.h:79
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
static constexpr int64_t kResourceNotFound
Definition: MCPError.h:31
std::function< void(const Notification &)> NotificationHandler
Definition: Server.h:60
llvm::Expected< Response > ToolsCallHandler(const Request &)
Definition: Server.cpp:117
const std::string m_version
Definition: Server.h:102
const std::string m_name
Definition: Server.h:101
void AddTool(std::unique_ptr< Tool > tool)
Definition: Server.cpp:72
void AddResourceProvider(std::unique_ptr< ResourceProvider > resource_provider)
Definition: Server.cpp:78
lldb_private::MainLoop & m_loop
Definition: Server.h:105
Server(std::string name, std::string version, std::unique_ptr< MCPTransport > transport_up, lldb_private::MainLoop &loop)
Definition: Server.cpp:29
llvm::StringMap< std::unique_ptr< Tool > > m_tools
Definition: Server.h:107
std::vector< std::unique_ptr< ResourceProvider > > m_resource_providers
Definition: Server.h:108
llvm::StringMap< NotificationHandler > m_notification_handlers
Definition: Server.h:111
llvm::StringMap< RequestHandler > m_request_handlers
Definition: Server.h:110
void OnError(llvm::Error) override
Called when an error occurs while reading from the transport.
Definition: Server.cpp:251
llvm::Expected< Response > ResourcesListHandler(const Request &)
Definition: Server.cpp:148
llvm::Expected< Response > ResourcesReadHandler(const Request &)
Definition: Server.cpp:162
llvm::Expected< Response > Handle(const Request &request)
Definition: Server.cpp:50
llvm::Expected< Response > ToolsListHandler(const Request &)
Definition: Server.cpp:105
void AddRequestHandler(llvm::StringRef method, RequestHandler handler)
Definition: Server.cpp:85
std::unique_ptr< MCPTransport > m_transport_up
Definition: Server.h:104
std::function< llvm::Expected< Response >(const Request &)> RequestHandler
Definition: Server.h:73
void Received(const Request &) override
Definition: Server.cpp:219
void OnClosed() override
Called on EOF or client disconnect.
Definition: Server.cpp:256
ServerCapabilities GetCapabilities()
Definition: Server.cpp:198
void AddNotificationHandler(llvm::StringRef method, NotificationHandler handler)
Definition: Server.cpp:89
llvm::Expected< Response > InitializeHandler(const Request &)
Definition: Server.cpp:94
llvm::json::Value toJSON(const Request &)
Definition: Protocol.cpp:66
std::variant< std::monostate, llvm::json::Value > ToolArguments
Definition: Protocol.h:190
static llvm::StringLiteral kProtocolVersion
Definition: Protocol.h:25
bool fromJSON(const llvm::json::Value &, Request &, llvm::json::Path)
Definition: Protocol.cpp:74
Definition: Debugger.h:58
Used by the client to invoke a tool provided by the server.
Definition: Protocol.h:291
std::optional< llvm::json::Value > arguments
Definition: Protocol.h:293
std::string name
Intended for programmatic or logical use, but used as a display name in past specs or fallback (if ti...
Definition: Protocol.h:197
After receiving an initialize request from the client, the server sends this response.
Definition: Protocol.h:255
std::string protocolVersion
The version of the Model Context Protocol that the server wants to use.
Definition: Protocol.h:259
ServerCapabilities capabilities
Definition: Protocol.h:261
The server’s response to a resources/list request from the client.
Definition: Protocol.h:126
std::vector< Resource > resources
Definition: Protocol.h:127
The server's response to a tools/list request from the client.
Definition: Protocol.h:280
std::vector< ToolDefinition > tools
Definition: Protocol.h:281
A notification which does not expect a response.
Definition: Protocol.h:88
std::string method
The method to be invoked.
Definition: Protocol.h:90
Sent from the client to the server, to read a specific resource URI.
Definition: Protocol.h:151
std::string uri
The URI of the resource to read.
Definition: Protocol.h:154
A request that expects a response.
Definition: Protocol.h:34
std::optional< llvm::json::Value > params
The method's params.
Definition: Protocol.h:40
std::string method
The method to be invoked.
Definition: Protocol.h:38
Id id
The request id.
Definition: Protocol.h:36
A known resource that the server is capable of reading.
Definition: Protocol.h:108
A response to a request, either an error or a result.
Definition: Protocol.h:76
Id id
The request id.
Definition: Protocol.h:78
std::variant< Error, llvm::json::Value > result
The result of the request, either an Error or the JSON value of the response.
Definition: Protocol.h:81
Capabilities that a server may support.
Definition: Protocol.h:224
Information about this instance of lldb's MCP server for lldb-mcp to use to coordinate connecting an ...
Definition: Server.h:46
std::string connection_uri
Definition: Server.h:47