[Lldb-commits] [lldb] [lldb] Adding structured types for existing MCP calls. (PR #155460)
via lldb-commits
lldb-commits at lists.llvm.org
Tue Aug 26 10:59:56 PDT 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-lldb
Author: John Harrison (ashgti)
<details>
<summary>Changes</summary>
This adds or renames existing types to match the names of the types on https://modelcontextprotocol.io/specification/2025-06-18/schema for the existing calls.
The new types are used in the unit tests and server implementation to remove the need for crafting various `llvm::json::Object` values by hand.
---
Patch is 52.89 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/155460.diff
12 Files Affected:
- (modified) lldb/include/lldb/Protocol/MCP/Protocol.h (+227-61)
- (modified) lldb/include/lldb/Protocol/MCP/Resource.h (+1-1)
- (modified) lldb/include/lldb/Protocol/MCP/Server.h (+1-1)
- (modified) lldb/include/lldb/Protocol/MCP/Tool.h (+2-1)
- (modified) lldb/source/Plugins/Protocol/MCP/Resource.cpp (+7-8)
- (modified) lldb/source/Plugins/Protocol/MCP/Resource.h (+9-6)
- (modified) lldb/source/Plugins/Protocol/MCP/Tool.cpp (+6-6)
- (modified) lldb/source/Plugins/Protocol/MCP/Tool.h (+4-4)
- (modified) lldb/source/Protocol/MCP/Protocol.cpp (+172-40)
- (modified) lldb/source/Protocol/MCP/Server.cpp (+34-39)
- (modified) lldb/unittests/Protocol/ProtocolMCPServerTest.cpp (+60-52)
- (modified) lldb/unittests/Protocol/ProtocolMCPTest.cpp (+25-38)
``````````diff
diff --git a/lldb/include/lldb/Protocol/MCP/Protocol.h b/lldb/include/lldb/Protocol/MCP/Protocol.h
index 49f9490221755..cdbdd67263e69 100644
--- a/lldb/include/lldb/Protocol/MCP/Protocol.h
+++ b/lldb/include/lldb/Protocol/MCP/Protocol.h
@@ -18,6 +18,7 @@
#include <optional>
#include <string>
#include <variant>
+#include <vector>
namespace lldb_protocol::mcp {
@@ -30,6 +31,9 @@ static llvm::StringLiteral kProtocolVersion = "2024-11-05";
using Id = std::variant<int64_t, std::string>;
/// A request that expects a response.
+///
+/// See
+/// https://modelcontextprotocol.io/specification/2025-06-18/schema#jsonrpcrequest
struct Request {
/// The request id.
Id id = 0;
@@ -38,11 +42,27 @@ struct Request {
/// The method's params.
std::optional<llvm::json::Value> params;
};
-
llvm::json::Value toJSON(const Request &);
bool fromJSON(const llvm::json::Value &, Request &, llvm::json::Path);
bool operator==(const Request &, const Request &);
+void PrintTo(const Request &req, std::ostream *os);
+
+enum ErrorCode : signed {
+ /// Invalid JSON was received by the server. An error occurred on the server
+ /// while parsing the JSON text.
+ eErrorCodeParseError = -32700,
+ /// The JSON sent is not a valid Request object.
+ eErrorCodeInvalidRequest = -32600,
+ /// The method does not exist / is not available.
+ eErrorCodeMethodNotFound = -32601,
+ /// Invalid method parameter(s).
+ eErrorCodeInvalidParams = -32602,
+ /// Internal JSON-RPC error.
+ eErrorCodeInternalError = -32603,
+};
+/// See
+/// https://modelcontextprotocol.io/specification/2025-06-18/schema#jsonrpcerror
struct Error {
/// The error type that occurred.
int64_t code = 0;
@@ -52,14 +72,16 @@ struct Error {
/// Additional information about the error. The value of this member is
/// defined by the sender (e.g. detailed error information, nested errors
/// etc.).
- std::optional<llvm::json::Value> data;
+ std::optional<llvm::json::Value> data = std::nullopt;
};
-
llvm::json::Value toJSON(const Error &);
bool fromJSON(const llvm::json::Value &, Error &, llvm::json::Path);
bool operator==(const Error &, const Error &);
/// A response to a request, either an error or a result.
+///
+/// See
+/// https://modelcontextprotocol.io/specification/2025-06-18/schema#jsonrpcrequest
struct Response {
/// The request id.
Id id = 0;
@@ -67,22 +89,24 @@ struct Response {
/// response.
std::variant<Error, llvm::json::Value> result;
};
-
llvm::json::Value toJSON(const Response &);
bool fromJSON(const llvm::json::Value &, Response &, llvm::json::Path);
bool operator==(const Response &, const Response &);
+void PrintTo(const Response &resp, std::ostream *os);
/// A notification which does not expect a response.
+/// See
+/// https://modelcontextprotocol.io/specification/2025-06-18/schema#jsonrpcnotification
struct Notification {
/// The method to be invoked.
std::string method;
/// The notification's params.
std::optional<llvm::json::Value> params;
};
-
llvm::json::Value toJSON(const Notification &);
bool fromJSON(const llvm::json::Value &, Notification &, llvm::json::Path);
bool operator==(const Notification &, const Notification &);
+void PrintTo(const Notification ¬e, std::ostream *os);
/// A general message as defined by the JSON-RPC 2.0 spec.
using Message = std::variant<Request, Response, Notification>;
@@ -90,46 +114,13 @@ using Message = std::variant<Request, Response, Notification>;
// not force it to be checked early here.
static_assert(std::is_convertible_v<Message, Message>,
"Message is not convertible to itself");
-
bool fromJSON(const llvm::json::Value &, Message &, llvm::json::Path);
llvm::json::Value toJSON(const Message &);
-
-struct ToolCapability {
- /// Whether this server supports notifications for changes to the tool list.
- bool listChanged = false;
-};
-
-llvm::json::Value toJSON(const ToolCapability &);
-bool fromJSON(const llvm::json::Value &, ToolCapability &, llvm::json::Path);
-
-struct ResourceCapability {
- /// Whether this server supports notifications for changes to the resources
- /// list.
- bool listChanged = false;
-
- /// Whether subscriptions are supported.
- bool subscribe = false;
-};
-
-llvm::json::Value toJSON(const ResourceCapability &);
-bool fromJSON(const llvm::json::Value &, ResourceCapability &,
- llvm::json::Path);
-
-/// Capabilities that a server may support. Known capabilities are defined here,
-/// in this schema, but this is not a closed set: any server can define its own,
-/// additional capabilities.
-struct Capabilities {
- /// Tool capabilities of the server.
- ToolCapability tools;
-
- /// Resource capabilities of the server.
- ResourceCapability resources;
-};
-
-llvm::json::Value toJSON(const Capabilities &);
-bool fromJSON(const llvm::json::Value &, Capabilities &, llvm::json::Path);
+void PrintTo(const Message &message, std::ostream *os);
/// A known resource that the server is capable of reading.
+///
+/// See https://modelcontextprotocol.io/specification/2025-06-18/schema#resource
struct Resource {
/// The URI of this resource.
std::string uri;
@@ -138,17 +129,28 @@ struct Resource {
std::string name;
/// A description of what this resource represents.
- std::string description;
+ std::string description = "";
/// The MIME type of this resource, if known.
- std::string mimeType;
+ std::string mimeType = "";
};
llvm::json::Value toJSON(const Resource &);
bool fromJSON(const llvm::json::Value &, Resource &, llvm::json::Path);
+/// The server’s response to a resources/list request from the client.
+///
+/// See
+/// https://modelcontextprotocol.io/specification/2025-06-18/schema#listresourcesresult
+struct ListResourcesResult {
+ std::vector<Resource> resources;
+};
+llvm::json::Value toJSON(const ListResourcesResult &);
+bool fromJSON(const llvm::json::Value &, ListResourcesResult &,
+ llvm::json::Path);
+
/// The contents of a specific resource or sub-resource.
-struct ResourceContents {
+struct TextResourceContents {
/// The URI of this resource.
std::string uri;
@@ -160,34 +162,45 @@ struct ResourceContents {
std::string mimeType;
};
-llvm::json::Value toJSON(const ResourceContents &);
-bool fromJSON(const llvm::json::Value &, ResourceContents &, llvm::json::Path);
+llvm::json::Value toJSON(const TextResourceContents &);
+bool fromJSON(const llvm::json::Value &, TextResourceContents &,
+ llvm::json::Path);
-/// The server's response to a resources/read request from the client.
-struct ResourceResult {
- std::vector<ResourceContents> contents;
+/// Sent from the client to the server, to read a specific resource URI.
+///
+/// See
+/// https://modelcontextprotocol.io/specification/2025-06-18/schema#readresourcerequest
+struct ReadResourceParams {
+ /// The URI of the resource to read. The URI can use any protocol; it is up to
+ /// the server how to interpret it.
+ std::string uri;
};
+llvm::json::Value toJSON(const ReadResourceParams &);
+bool fromJSON(const llvm::json::Value &, ReadResourceParams &,
+ llvm::json::Path);
-llvm::json::Value toJSON(const ResourceResult &);
-bool fromJSON(const llvm::json::Value &, ResourceResult &, llvm::json::Path);
+/// The server's response to a resources/read request from the client.
+struct ReadResourceResult {
+ std::vector<TextResourceContents> contents;
+};
+llvm::json::Value toJSON(const ReadResourceResult &);
+bool fromJSON(const llvm::json::Value &, ReadResourceResult &,
+ llvm::json::Path);
/// Text provided to or from an LLM.
+///
+/// See
+/// https://modelcontextprotocol.io/specification/2025-06-18/schema#textcontent
struct TextContent {
/// The text content of the message.
std::string text;
};
-
llvm::json::Value toJSON(const TextContent &);
bool fromJSON(const llvm::json::Value &, TextContent &, llvm::json::Path);
-struct TextResult {
- std::vector<TextContent> content;
- bool isError = false;
-};
-
-llvm::json::Value toJSON(const TextResult &);
-bool fromJSON(const llvm::json::Value &, TextResult &, llvm::json::Path);
-
+/// Definition for a tool the client can call.
+///
+/// See https://modelcontextprotocol.io/specification/2025-06-18/schema#tool
struct ToolDefinition {
/// Unique identifier for the tool.
std::string name;
@@ -198,12 +211,165 @@ struct ToolDefinition {
// JSON Schema for the tool's parameters.
std::optional<llvm::json::Value> inputSchema;
};
-
llvm::json::Value toJSON(const ToolDefinition &);
bool fromJSON(const llvm::json::Value &, ToolDefinition &, llvm::json::Path);
using ToolArguments = std::variant<std::monostate, llvm::json::Value>;
+/// Describes the name and version of an MCP implementation, with an optional
+/// title for UI representation.
+///
+/// see
+/// https://modelcontextprotocol.io/specification/2025-06-18/schema#implementation
+struct Implementation {
+ /// Intended for programmatic or logical use, but used as a display name in
+ /// past specs or fallback (if title isn’t present).
+ std::string name;
+
+ std::string version;
+
+ /// Intended for UI and end-user contexts — optimized to be human-readable and
+ /// easily understood, even by those unfamiliar with domain-specific
+ /// terminology.
+ ///
+ /// If not provided, the name should be used for display (except for Tool,
+ /// where annotations.title should be given precedence over using name, if
+ /// present).
+ std::string title = "";
+};
+llvm::json::Value toJSON(const Implementation &);
+bool fromJSON(const llvm::json::Value &, Implementation &, llvm::json::Path);
+
+/// Capabilities a client may support. Known capabilities are defined here, in
+/// this schema, but this is not a closed set: any client can define its own,
+/// additional capabilities.
+///
+/// See
+/// https://modelcontextprotocol.io/specification/2025-06-18/schema#clientcapabilities
+struct ClientCapabilities {};
+llvm::json::Value toJSON(const ClientCapabilities &);
+bool fromJSON(const llvm::json::Value &, ClientCapabilities &,
+ llvm::json::Path);
+
+/// Capabilities that a server may support. Known capabilities are defined here,
+/// in this schema, but this is not a closed set: any server can define its own,
+/// additional capabilities.
+///
+/// See
+/// https://modelcontextprotocol.io/specification/2025-06-18/schema#servercapabilities
+struct ServerCapabilities {
+ bool supportsToolsList = false;
+ bool supportsResourcesList = false;
+ bool supportsResourcesSubscribe = false;
+
+ /// Utilities.
+ bool supportsCompletions = false;
+ bool supportsLogging = false;
+};
+llvm::json::Value toJSON(const ServerCapabilities &);
+bool fromJSON(const llvm::json::Value &, ServerCapabilities &,
+ llvm::json::Path);
+
+/// Initialization
+
+/// This request is sent from the client to the server when it first connects,
+/// asking it to begin initialization.
+///
+/// See
+/// https://modelcontextprotocol.io/specification/2025-06-18/schema#initializerequest
+struct InitializeParams {
+ /// The latest version of the Model Context Protocol that the client supports.
+ /// The client MAY decide to support older versions as well.
+ std::string protocolVersion;
+
+ ClientCapabilities capabilities;
+
+ Implementation clientInfo;
+};
+llvm::json::Value toJSON(const InitializeParams &);
+bool fromJSON(const llvm::json::Value &, InitializeParams &, llvm::json::Path);
+
+/// After receiving an initialize request from the client, the server sends this
+/// response.
+///
+/// See
+/// https://modelcontextprotocol.io/specification/2025-06-18/schema#initializeresult
+struct InitializeResult {
+ /// The version of the Model Context Protocol that the server wants to use.
+ /// This may not match the version that the client requested. If the client
+ /// cannot support this version, it MUST disconnect.
+ std::string protocolVersion;
+
+ ServerCapabilities capabilities;
+ Implementation serverInfo;
+
+ /// Instructions describing how to use the server and its features.
+ ///
+ /// This can be used by clients to improve the LLM's understanding of
+ /// available tools, resources, etc. It can be thought of like a "hint" to the
+ /// model. For example, this information MAY be added to the system prompt.
+ std::string instructions = "";
+};
+llvm::json::Value toJSON(const InitializeResult &);
+bool fromJSON(const llvm::json::Value &, InitializeResult &, llvm::json::Path);
+
+/// Special case parameter or result that has no value.
+using Void = std::monostate;
+llvm::json::Value toJSON(const Void &);
+bool fromJSON(const llvm::json::Value &, Void &, llvm::json::Path);
+
+/// The server's response to a `tools/list` request from the client.
+///
+/// See
+/// https://modelcontextprotocol.io/specification/2025-06-18/schema#listtoolsresult
+struct ListToolsResult {
+ std::vector<ToolDefinition> tools;
+};
+llvm::json::Value toJSON(const ListToolsResult &);
+bool fromJSON(const llvm::json::Value &, ListToolsResult &, llvm::json::Path);
+
+/// Supported content types, currently only TextContent, but the spec includes
+/// additional content types.
+using ContentBlock = TextContent;
+
+/// Used by the client to invoke a tool provided by the server.
+struct CallToolParams {
+ std::string name;
+ std::optional<llvm::json::Value> arguments;
+};
+llvm::json::Value toJSON(const CallToolParams &);
+bool fromJSON(const llvm::json::Value &, CallToolParams &, llvm::json::Path);
+
+/// The server’s response to a tool call.
+///
+/// See
+/// https://modelcontextprotocol.io/specification/2025-06-18/schema#calltoolresult
+struct CallToolResult {
+ /// A list of content objects that represent the unstructured result of the
+ /// tool call.
+ std::vector<ContentBlock> content;
+
+ /// Whether the tool call ended in an error.
+ ///
+ /// If not set, this is assumed to be false (the call was successful).
+ ///
+ /// Any errors that originate from the tool SHOULD be reported inside the
+ /// result object, with `isError` set to true, not as an MCP protocol-level
+ /// error response. Otherwise, the LLM would not be able to see that an error
+ /// occurred and self-correct.
+ ///
+ /// However, any errors in finding the tool, an error indicating that the
+ /// server does not support tool calls, or any other exceptional conditions,
+ /// should be reported as an MCP error response.
+ bool isError = false;
+
+ /// An optional JSON object that represents the structured result of the tool
+ /// call.
+ std::optional<llvm::json::Value> structuredContent = std::nullopt;
+};
+llvm::json::Value toJSON(const CallToolResult &);
+bool fromJSON(const llvm::json::Value &, CallToolResult &, llvm::json::Path);
+
} // namespace lldb_protocol::mcp
#endif
diff --git a/lldb/include/lldb/Protocol/MCP/Resource.h b/lldb/include/lldb/Protocol/MCP/Resource.h
index 4835d340cd4c6..158cffc71ea10 100644
--- a/lldb/include/lldb/Protocol/MCP/Resource.h
+++ b/lldb/include/lldb/Protocol/MCP/Resource.h
@@ -20,7 +20,7 @@ class ResourceProvider {
virtual ~ResourceProvider() = default;
virtual std::vector<lldb_protocol::mcp::Resource> GetResources() const = 0;
- virtual llvm::Expected<lldb_protocol::mcp::ResourceResult>
+ virtual llvm::Expected<lldb_protocol::mcp::ReadResourceResult>
ReadResource(llvm::StringRef uri) const = 0;
};
diff --git a/lldb/include/lldb/Protocol/MCP/Server.h b/lldb/include/lldb/Protocol/MCP/Server.h
index 2b9e919329752..aa5714e45755e 100644
--- a/lldb/include/lldb/Protocol/MCP/Server.h
+++ b/lldb/include/lldb/Protocol/MCP/Server.h
@@ -58,7 +58,7 @@ class Server : public MCPTransport::MessageHandler {
llvm::Error Run();
protected:
- Capabilities GetCapabilities();
+ ServerCapabilities GetCapabilities();
using RequestHandler =
std::function<llvm::Expected<Response>(const Request &)>;
diff --git a/lldb/include/lldb/Protocol/MCP/Tool.h b/lldb/include/lldb/Protocol/MCP/Tool.h
index 96669d1357166..6c9f05161f8e7 100644
--- a/lldb/include/lldb/Protocol/MCP/Tool.h
+++ b/lldb/include/lldb/Protocol/MCP/Tool.h
@@ -10,6 +10,7 @@
#define LLDB_PROTOCOL_MCP_TOOL_H
#include "lldb/Protocol/MCP/Protocol.h"
+#include "llvm/Support/Error.h"
#include "llvm/Support/JSON.h"
#include <string>
@@ -20,7 +21,7 @@ class Tool {
Tool(std::string name, std::string description);
virtual ~Tool() = default;
- virtual llvm::Expected<lldb_protocol::mcp::TextResult>
+ virtual llvm::Expected<lldb_protocol::mcp::CallToolResult>
Call(const lldb_protocol::mcp::ToolArguments &args) = 0;
virtual std::optional<llvm::json::Value> GetSchema() const {
diff --git a/lldb/source/Plugins/Protocol/MCP/Resource.cpp b/lldb/source/Plugins/Protocol/MCP/Resource.cpp
index e94d2cdd65e07..581424510d4cf 100644
--- a/lldb/source/Plugins/Protocol/MCP/Resource.cpp
+++ b/lldb/source/Plugins/Protocol/MCP/Resource.cpp
@@ -8,7 +8,6 @@
#include "lldb/Core/Debugger.h"
#include "lldb/Core/Module.h"
#include "lldb/Protocol/MCP/MCPError.h"
-#include "lldb/Target/Platform.h"
using namespace lldb_private;
using namespace lldb_private::mcp;
@@ -124,7 +123,7 @@ DebuggerResourceProvider::GetResources() const {
return resources;
}
-llvm::Expected<lldb_protocol::mcp::ResourceResult>
+llvm::Expected<lldb_protocol::mcp::ReadResourceResult>
DebuggerResourceProvider::ReadResource(llvm::StringRef uri) const {
auto [protocol, path] = uri.split("://");
@@ -161,7 +160,7 @@ DebuggerResourceProvider::ReadResource(llvm::StringRef uri) const {
return ReadDebuggerResource(uri, debugger_idx);
}
-llvm::Expected<lldb_protocol::mcp::ResourceResult>
+llvm::Expected<lldb_protocol::mcp::ReadResourceResult>
DebuggerResourceProvider::ReadDebuggerResource(llvm::StringRef uri,
lldb::user_id_t debugger_id) {
lldb::DebuggerSP debugger_sp = Debugger::FindDebuggerWithID(debugger_id);
@@ -173,17 +172,17 @@ DebuggerResourceProvider::ReadDebuggerResource(llvm::StringRef uri,
debugger_resource.name = debugger_sp->GetInstanceName();
debugger_resource.num_targets = debugger_sp->GetTargetList().GetNumTargets();
- lldb_protocol::mcp::ResourceContents contents;
+ lldb_protocol::mcp::TextResourceContents contents;
contents.uri = uri;
contents.mimeType = kMimeTypeJSON;
contents.text = llvm::formatv("{0}", toJSON(debugger_resource));
- lldb_protocol::mcp::ResourceResult result;
+ lldb_protocol::mcp::ReadResourceResult result;
result.contents.push_back(contents);
return result;
}
-llvm::Expected<lldb_protocol::mcp::ResourceResult>
+llvm::Expected<lldb_protocol::mcp::ReadResourceResult>
DebuggerResourceProvider::ReadTargetResource(llvm::StringRef uri,
lldb::user_id_t debugger_id,
size_t target_idx) {
@@ -209,12 +208,12 @@ DebuggerResourceProvider::ReadTargetResource(llvm::StringRef uri,
if (lldb::PlatformSP platform_sp = target_sp->GetPlatform())
target_resource.platform = platform_sp->GetName();
- lldb_protocol::mcp::ResourceContents contents;
+ lldb_protocol::mcp::TextResourceContents contents;
contents.uri = uri;
contents.mimeType = kMimeTypeJSON;
contents.text = llvm::formatv("{0}", toJSON(target_resource));
- lldb_protocol::mcp::ResourceResult result;
+ lldb_protocol::mcp::ReadResourceResult result;
result.contents.push_back(contents);
return result;
}
diff --git a/lldb/source/Plugins/Protocol/MCP/Resource.h b/lldb/source/Plugins/Protocol/MCP/Resource.h
index e2382a74f796b..0c6576602905e 100644
--- a/lldb/source/Plugins/Protocol/MCP/Resource.h
+++ b/lldb/source/Plugins/Protocol/MCP/Resource.h
@@ -11,7 +11,11 @@
#include "lldb/Protocol/MCP/Protocol.h"
#include "lldb/Protocol/MCP/Resource.h"
-#include "lldb/lldb-private.h"
+#include "lldb/lldb-forward.h"
+#include "lldb/lldb-types.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Error.h"
+#include <cstddef>
#include <vector>
namespace lldb_private::mcp {
@@ -21,9 +25,8 @@ class DebuggerResourceProvider : public lldb_protocol::mcp::ResourceProvider {
using ResourceProvider::ResourceProvider;
virtual ~DebuggerResourceProvider() = default;
- virtual std::vector<lldb_protocol::mcp::Resource>
- GetResources() const override;
- virtual llvm::Expected<lldb_protocol::mcp::ResourceResult>
+ std::vector<lldb_...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/155460
More information about the lldb-commits
mailing list