-
Notifications
You must be signed in to change notification settings - Fork 14.7k
[lldb] Move MCP protocol into its own library (NFC) #152059
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
This PR moves the MCP protocol code into its own library (`lldbProtocolMCP`) so the code can be shared between the `ProtocolServer` plugin in LLDB as well as `lldb-mcp`. The goal is to do the same thing for DAP (which would be used exclusively from `lldb-dap`). To make it clear that it's neither part of the `lldb` nor the `lldb_private` namespace, I created a new `lldb_protocol` namespace. Depending on how much code would be reused by lldb-dap, we may move more code into the protocol library.
@llvm/pr-subscribers-lldb Author: Jonas Devlieghere (JDevlieghere) ChangesThis PR moves the MCP protocol code into its own library ( To make it clear that it's neither part of the Depending on how much code would be reused by lldb-dap, we may move more code into the protocol library. Patch is 34.20 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/152059.diff 19 Files Affected:
diff --git a/lldb/source/Plugins/Protocol/MCP/Protocol.h b/lldb/include/lldb/Protocol/MCP/Protocol.h
similarity index 96%
rename from lldb/source/Plugins/Protocol/MCP/Protocol.h
rename to lldb/include/lldb/Protocol/MCP/Protocol.h
index ce74836e62541..c43b06809bd3f 100644
--- a/lldb/source/Plugins/Protocol/MCP/Protocol.h
+++ b/lldb/include/lldb/Protocol/MCP/Protocol.h
@@ -11,15 +11,15 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLDB_PLUGINS_PROTOCOL_MCP_PROTOCOL_H
-#define LLDB_PLUGINS_PROTOCOL_MCP_PROTOCOL_H
+#ifndef LLDB_PROTOCOL_MCP_PROTOCOL_H
+#define LLDB_PROTOCOL_MCP_PROTOCOL_H
#include "llvm/Support/JSON.h"
#include <optional>
#include <string>
#include <variant>
-namespace lldb_private::mcp::protocol {
+namespace lldb_protocol::mcp {
static llvm::StringLiteral kVersion = "2024-11-05";
@@ -183,6 +183,6 @@ llvm::json::Value toJSON(const Message &);
using ToolArguments = std::variant<std::monostate, llvm::json::Value>;
-} // namespace lldb_private::mcp::protocol
+} // namespace lldb_protocol::mcp
#endif
diff --git a/lldb/source/CMakeLists.txt b/lldb/source/CMakeLists.txt
index 51c9f9c90826e..ae02227ca3578 100644
--- a/lldb/source/CMakeLists.txt
+++ b/lldb/source/CMakeLists.txt
@@ -10,6 +10,7 @@ add_subdirectory(Host)
add_subdirectory(Initialization)
add_subdirectory(Interpreter)
add_subdirectory(Plugins)
+add_subdirectory(Protocol)
add_subdirectory(Symbol)
add_subdirectory(Target)
add_subdirectory(Utility)
diff --git a/lldb/source/Plugins/Protocol/MCP/CMakeLists.txt b/lldb/source/Plugins/Protocol/MCP/CMakeLists.txt
index e104fb527e57a..2740c0825a8c2 100644
--- a/lldb/source/Plugins/Protocol/MCP/CMakeLists.txt
+++ b/lldb/source/Plugins/Protocol/MCP/CMakeLists.txt
@@ -1,6 +1,5 @@
add_lldb_library(lldbPluginProtocolServerMCP PLUGIN
MCPError.cpp
- Protocol.cpp
ProtocolServerMCP.cpp
Resource.cpp
Tool.cpp
@@ -10,5 +9,6 @@ add_lldb_library(lldbPluginProtocolServerMCP PLUGIN
LINK_LIBS
lldbHost
+ lldbProtocolMCP
lldbUtility
)
diff --git a/lldb/source/Plugins/Protocol/MCP/MCPError.cpp b/lldb/source/Plugins/Protocol/MCP/MCPError.cpp
index 659b53a14fe23..71f71b7b69e89 100644
--- a/lldb/source/Plugins/Protocol/MCP/MCPError.cpp
+++ b/lldb/source/Plugins/Protocol/MCP/MCPError.cpp
@@ -25,8 +25,8 @@ std::error_code MCPError::convertToErrorCode() const {
return llvm::inconvertibleErrorCode();
}
-protocol::Error MCPError::toProtcolError() const {
- protocol::Error error;
+lldb_protocol::mcp::Error MCPError::toProtcolError() const {
+ lldb_protocol::mcp::Error error;
error.error.code = m_error_code;
error.error.message = m_message;
return error;
diff --git a/lldb/source/Plugins/Protocol/MCP/MCPError.h b/lldb/source/Plugins/Protocol/MCP/MCPError.h
index f4db13d6deade..c93e959574938 100644
--- a/lldb/source/Plugins/Protocol/MCP/MCPError.h
+++ b/lldb/source/Plugins/Protocol/MCP/MCPError.h
@@ -6,7 +6,7 @@
//
//===----------------------------------------------------------------------===//
-#include "Protocol.h"
+#include "lldb/Protocol/MCP/Protocol.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/FormatVariadic.h"
#include <string>
@@ -24,7 +24,7 @@ class MCPError : public llvm::ErrorInfo<MCPError> {
const std::string &getMessage() const { return m_message; }
- protocol::Error toProtcolError() const;
+ lldb_protocol::mcp::Error toProtcolError() const;
static constexpr int64_t kResourceNotFound = -32002;
static constexpr int64_t kInternalError = -32603;
diff --git a/lldb/source/Plugins/Protocol/MCP/ProtocolServerMCP.cpp b/lldb/source/Plugins/Protocol/MCP/ProtocolServerMCP.cpp
index 0e5a3631e6387..4d517ee8158c4 100644
--- a/lldb/source/Plugins/Protocol/MCP/ProtocolServerMCP.cpp
+++ b/lldb/source/Plugins/Protocol/MCP/ProtocolServerMCP.cpp
@@ -42,10 +42,11 @@ ProtocolServerMCP::ProtocolServerMCP() : ProtocolServer() {
AddRequestHandler("resources/read",
std::bind(&ProtocolServerMCP::ResourcesReadHandler, this,
std::placeholders::_1));
- AddNotificationHandler(
- "notifications/initialized", [](const protocol::Notification &) {
- LLDB_LOG(GetLog(LLDBLog::Host), "MCP initialization complete");
- });
+ AddNotificationHandler("notifications/initialized",
+ [](const lldb_protocol::mcp::Notification &) {
+ LLDB_LOG(GetLog(LLDBLog::Host),
+ "MCP initialization complete");
+ });
AddTool(
std::make_unique<CommandTool>("lldb_command", "Run an lldb command."));
@@ -72,11 +73,11 @@ llvm::StringRef ProtocolServerMCP::GetPluginDescriptionStatic() {
return "MCP Server.";
}
-llvm::Expected<protocol::Response>
-ProtocolServerMCP::Handle(protocol::Request request) {
+llvm::Expected<lldb_protocol::mcp::Response>
+ProtocolServerMCP::Handle(lldb_protocol::mcp::Request request) {
auto it = m_request_handlers.find(request.method);
if (it != m_request_handlers.end()) {
- llvm::Expected<protocol::Response> response = it->second(request);
+ llvm::Expected<lldb_protocol::mcp::Response> response = it->second(request);
if (!response)
return response;
response->id = request.id;
@@ -87,7 +88,7 @@ ProtocolServerMCP::Handle(protocol::Request request) {
llvm::formatv("no handler for request: {0}", request.method).str());
}
-void ProtocolServerMCP::Handle(protocol::Notification notification) {
+void ProtocolServerMCP::Handle(lldb_protocol::mcp::Notification notification) {
auto it = m_notification_handlers.find(notification.method);
if (it != m_notification_handlers.end()) {
it->second(notification);
@@ -133,7 +134,7 @@ llvm::Error ProtocolServerMCP::ReadCallback(Client &client) {
for (std::string::size_type pos;
(pos = client.buffer.find('\n')) != std::string::npos;) {
- llvm::Expected<std::optional<protocol::Message>> message =
+ llvm::Expected<std::optional<lldb_protocol::mcp::Message>> message =
HandleData(StringRef(client.buffer.data(), pos));
client.buffer = client.buffer.erase(0, pos + 1);
if (!message)
@@ -208,19 +209,19 @@ llvm::Error ProtocolServerMCP::Stop() {
return llvm::Error::success();
}
-llvm::Expected<std::optional<protocol::Message>>
+llvm::Expected<std::optional<lldb_protocol::mcp::Message>>
ProtocolServerMCP::HandleData(llvm::StringRef data) {
- auto message = llvm::json::parse<protocol::Message>(/*JSON=*/data);
+ auto message = llvm::json::parse<lldb_protocol::mcp::Message>(/*JSON=*/data);
if (!message)
return message.takeError();
- if (const protocol::Request *request =
- std::get_if<protocol::Request>(&(*message))) {
- llvm::Expected<protocol::Response> response = Handle(*request);
+ if (const lldb_protocol::mcp::Request *request =
+ std::get_if<lldb_protocol::mcp::Request>(&(*message))) {
+ llvm::Expected<lldb_protocol::mcp::Response> response = Handle(*request);
// Handle failures by converting them into an Error message.
if (!response) {
- protocol::Error protocol_error;
+ lldb_protocol::mcp::Error protocol_error;
llvm::handleAllErrors(
response.takeError(),
[&](const MCPError &err) { protocol_error = err.toProtcolError(); },
@@ -235,23 +236,23 @@ ProtocolServerMCP::HandleData(llvm::StringRef data) {
return *response;
}
- if (const protocol::Notification *notification =
- std::get_if<protocol::Notification>(&(*message))) {
+ if (const lldb_protocol::mcp::Notification *notification =
+ std::get_if<lldb_protocol::mcp::Notification>(&(*message))) {
Handle(*notification);
return std::nullopt;
}
- if (std::get_if<protocol::Error>(&(*message)))
+ if (std::get_if<lldb_protocol::mcp::Error>(&(*message)))
return llvm::createStringError("unexpected MCP message: error");
- if (std::get_if<protocol::Response>(&(*message)))
+ if (std::get_if<lldb_protocol::mcp::Response>(&(*message)))
return llvm::createStringError("unexpected MCP message: response");
llvm_unreachable("all message types handled");
}
-protocol::Capabilities ProtocolServerMCP::GetCapabilities() {
- protocol::Capabilities capabilities;
+lldb_protocol::mcp::Capabilities ProtocolServerMCP::GetCapabilities() {
+ lldb_protocol::mcp::Capabilities capabilities;
capabilities.tools.listChanged = true;
// FIXME: Support sending notifications when a debugger/target are
// added/removed.
@@ -288,20 +289,22 @@ void ProtocolServerMCP::AddNotificationHandler(llvm::StringRef method,
m_notification_handlers[method] = std::move(handler);
}
-llvm::Expected<protocol::Response>
-ProtocolServerMCP::InitializeHandler(const protocol::Request &request) {
- protocol::Response response;
+llvm::Expected<lldb_protocol::mcp::Response>
+ProtocolServerMCP::InitializeHandler(
+ const lldb_protocol::mcp::Request &request) {
+ lldb_protocol::mcp::Response response;
response.result.emplace(llvm::json::Object{
- {"protocolVersion", protocol::kVersion},
+ {"protocolVersion", lldb_protocol::mcp::kVersion},
{"capabilities", GetCapabilities()},
{"serverInfo",
llvm::json::Object{{"name", kName}, {"version", kVersion}}}});
return response;
}
-llvm::Expected<protocol::Response>
-ProtocolServerMCP::ToolsListHandler(const protocol::Request &request) {
- protocol::Response response;
+llvm::Expected<lldb_protocol::mcp::Response>
+ProtocolServerMCP::ToolsListHandler(
+ const lldb_protocol::mcp::Request &request) {
+ lldb_protocol::mcp::Response response;
llvm::json::Array tools;
for (const auto &tool : m_tools)
@@ -312,9 +315,10 @@ ProtocolServerMCP::ToolsListHandler(const protocol::Request &request) {
return response;
}
-llvm::Expected<protocol::Response>
-ProtocolServerMCP::ToolsCallHandler(const protocol::Request &request) {
- protocol::Response response;
+llvm::Expected<lldb_protocol::mcp::Response>
+ProtocolServerMCP::ToolsCallHandler(
+ const lldb_protocol::mcp::Request &request) {
+ lldb_protocol::mcp::Response response;
if (!request.params)
return llvm::createStringError("no tool parameters");
@@ -335,11 +339,11 @@ ProtocolServerMCP::ToolsCallHandler(const protocol::Request &request) {
if (it == m_tools.end())
return llvm::createStringError(llvm::formatv("no tool \"{0}\"", tool_name));
- protocol::ToolArguments tool_args;
+ lldb_protocol::mcp::ToolArguments tool_args;
if (const json::Value *args = param_obj->get("arguments"))
tool_args = *args;
- llvm::Expected<protocol::TextResult> text_result =
+ llvm::Expected<lldb_protocol::mcp::TextResult> text_result =
it->second->Call(tool_args);
if (!text_result)
return text_result.takeError();
@@ -349,16 +353,17 @@ ProtocolServerMCP::ToolsCallHandler(const protocol::Request &request) {
return response;
}
-llvm::Expected<protocol::Response>
-ProtocolServerMCP::ResourcesListHandler(const protocol::Request &request) {
- protocol::Response response;
+llvm::Expected<lldb_protocol::mcp::Response>
+ProtocolServerMCP::ResourcesListHandler(
+ const lldb_protocol::mcp::Request &request) {
+ lldb_protocol::mcp::Response response;
llvm::json::Array resources;
std::lock_guard<std::mutex> guard(m_server_mutex);
for (std::unique_ptr<ResourceProvider> &resource_provider_up :
m_resource_providers) {
- for (const protocol::Resource &resource :
+ for (const lldb_protocol::mcp::Resource &resource :
resource_provider_up->GetResources())
resources.push_back(resource);
}
@@ -368,9 +373,10 @@ ProtocolServerMCP::ResourcesListHandler(const protocol::Request &request) {
return response;
}
-llvm::Expected<protocol::Response>
-ProtocolServerMCP::ResourcesReadHandler(const protocol::Request &request) {
- protocol::Response response;
+llvm::Expected<lldb_protocol::mcp::Response>
+ProtocolServerMCP::ResourcesReadHandler(
+ const lldb_protocol::mcp::Request &request) {
+ lldb_protocol::mcp::Response response;
if (!request.params)
return llvm::createStringError("no resource parameters");
@@ -390,7 +396,7 @@ ProtocolServerMCP::ResourcesReadHandler(const protocol::Request &request) {
std::lock_guard<std::mutex> guard(m_server_mutex);
for (std::unique_ptr<ResourceProvider> &resource_provider_up :
m_resource_providers) {
- llvm::Expected<protocol::ResourceResult> result =
+ llvm::Expected<lldb_protocol::mcp::ResourceResult> result =
resource_provider_up->ReadResource(uri_str);
if (result.errorIsA<UnsupportedURI>()) {
llvm::consumeError(result.takeError());
@@ -399,7 +405,7 @@ ProtocolServerMCP::ResourcesReadHandler(const protocol::Request &request) {
if (!result)
return result.takeError();
- protocol::Response response;
+ lldb_protocol::mcp::Response response;
response.result.emplace(std::move(*result));
return response;
}
diff --git a/lldb/source/Plugins/Protocol/MCP/ProtocolServerMCP.h b/lldb/source/Plugins/Protocol/MCP/ProtocolServerMCP.h
index e273f6e2a8d37..611e62af5c8cb 100644
--- a/lldb/source/Plugins/Protocol/MCP/ProtocolServerMCP.h
+++ b/lldb/source/Plugins/Protocol/MCP/ProtocolServerMCP.h
@@ -9,12 +9,12 @@
#ifndef LLDB_PLUGINS_PROTOCOL_MCP_PROTOCOLSERVERMCP_H
#define LLDB_PLUGINS_PROTOCOL_MCP_PROTOCOLSERVERMCP_H
-#include "Protocol.h"
#include "Resource.h"
#include "Tool.h"
#include "lldb/Core/ProtocolServer.h"
#include "lldb/Host/MainLoop.h"
#include "lldb/Host/Socket.h"
+#include "lldb/Protocol/MCP/Protocol.h"
#include "llvm/ADT/StringMap.h"
#include <thread>
@@ -41,10 +41,11 @@ class ProtocolServerMCP : public ProtocolServer {
Socket *GetSocket() const override { return m_listener.get(); }
protected:
- using RequestHandler = std::function<llvm::Expected<protocol::Response>(
- const protocol::Request &)>;
+ using RequestHandler =
+ std::function<llvm::Expected<lldb_protocol::mcp::Response>(
+ const lldb_protocol::mcp::Request &)>;
using NotificationHandler =
- std::function<void(const protocol::Notification &)>;
+ std::function<void(const lldb_protocol::mcp::Notification &)>;
void AddTool(std::unique_ptr<Tool> tool);
void AddResourceProvider(std::unique_ptr<ResourceProvider> resource_provider);
@@ -56,26 +57,27 @@ class ProtocolServerMCP : public ProtocolServer {
private:
void AcceptCallback(std::unique_ptr<Socket> socket);
- llvm::Expected<std::optional<protocol::Message>>
+ llvm::Expected<std::optional<lldb_protocol::mcp::Message>>
HandleData(llvm::StringRef data);
- llvm::Expected<protocol::Response> Handle(protocol::Request request);
- void Handle(protocol::Notification notification);
+ llvm::Expected<lldb_protocol::mcp::Response>
+ Handle(lldb_protocol::mcp::Request request);
+ void Handle(lldb_protocol::mcp::Notification notification);
- llvm::Expected<protocol::Response>
- InitializeHandler(const protocol::Request &);
+ llvm::Expected<lldb_protocol::mcp::Response>
+ InitializeHandler(const lldb_protocol::mcp::Request &);
- llvm::Expected<protocol::Response>
- ToolsListHandler(const protocol::Request &);
- llvm::Expected<protocol::Response>
- ToolsCallHandler(const protocol::Request &);
+ llvm::Expected<lldb_protocol::mcp::Response>
+ ToolsListHandler(const lldb_protocol::mcp::Request &);
+ llvm::Expected<lldb_protocol::mcp::Response>
+ ToolsCallHandler(const lldb_protocol::mcp::Request &);
- llvm::Expected<protocol::Response>
- ResourcesListHandler(const protocol::Request &);
- llvm::Expected<protocol::Response>
- ResourcesReadHandler(const protocol::Request &);
+ llvm::Expected<lldb_protocol::mcp::Response>
+ ResourcesListHandler(const lldb_protocol::mcp::Request &);
+ llvm::Expected<lldb_protocol::mcp::Response>
+ ResourcesReadHandler(const lldb_protocol::mcp::Request &);
- protocol::Capabilities GetCapabilities();
+ lldb_protocol::mcp::Capabilities GetCapabilities();
llvm::StringLiteral kName = "lldb-mcp";
llvm::StringLiteral kVersion = "0.1.0";
diff --git a/lldb/source/Plugins/Protocol/MCP/Resource.cpp b/lldb/source/Plugins/Protocol/MCP/Resource.cpp
index d75d5b6dd6a41..bc39e1b0c0ed2 100644
--- a/lldb/source/Plugins/Protocol/MCP/Resource.cpp
+++ b/lldb/source/Plugins/Protocol/MCP/Resource.cpp
@@ -10,6 +10,7 @@
#include "lldb/Core/Module.h"
#include "lldb/Target/Platform.h"
+using namespace lldb_private;
using namespace lldb_private::mcp;
namespace {
@@ -64,11 +65,11 @@ static llvm::Error createUnsupportedURIError(llvm::StringRef uri) {
return llvm::make_error<UnsupportedURI>(uri.str());
}
-protocol::Resource
+lldb_protocol::mcp::Resource
DebuggerResourceProvider::GetDebuggerResource(Debugger &debugger) {
const lldb::user_id_t debugger_id = debugger.GetID();
- protocol::Resource resource;
+ lldb_protocol::mcp::Resource resource;
resource.uri = llvm::formatv("lldb://debugger/{0}", debugger_id);
resource.name = debugger.GetInstanceName();
resource.description =
@@ -78,7 +79,7 @@ DebuggerResourceProvider::GetDebuggerResource(Debugger &debugger) {
return resource;
}
-protocol::Resource
+lldb_protocol::mcp::Resource
DebuggerResourceProvider::GetTargetResource(size_t target_idx, Target &target) {
const size_t debugger_id = target.GetDebugger().GetID();
@@ -87,7 +88,7 @@ DebuggerResourceProvider::GetTargetResource(size_t target_idx, Target &target) {
if (Module *exe_module = target.GetExecutableModulePointer())
target_name = exe_module->GetFileSpec().GetFilename().GetString();
- protocol::Resource resource;
+ lldb_protocol::mcp::Resource resource;
resource.uri =
llvm::formatv("lldb://debugger/{0}/target/{1}", debugger_id, target_idx);
resource.name = target_name;
@@ -98,8 +99,9 @@ DebuggerResourceProvider::GetTargetResource(size_t target_idx, Target &target) {
return resource;
}
-std::vector<protocol::Resource> DebuggerResourceProvider::GetResources() const {
- std::vector<protocol::Resource> resources;
+std::vector<lldb_protocol::mcp::Resource>
+DebuggerResourceProvider::GetResources() const {
+ std::vector<lldb_protocol::mcp::Resource> resources;
const size_t num_debuggers = Debugger::GetNumDebuggers();
for (size_t i = 0; i < num_debuggers; ++i) {
@@ -121,7 +123,7 @@ std::vector<protocol::Resource> DebuggerResourceProvider::GetResources() const {
return resources;
}
-llvm::Expected<protocol::ResourceResult>
+llvm::Expected<lldb_protocol::mcp::ResourceResult>
DebuggerResourceProvider::ReadResource(llvm::StringRef uri) const {
auto [protocol, path] = uri.split("://");
@@ -158,7 +160,7 @@ DebuggerResourceProvider::ReadResource(llvm::StringRef uri) const {
return ReadDebuggerResource(uri, debugger_idx);
}
-llvm::Expected<protocol::ResourceResult>
+llvm::Expected<lldb_protocol::mcp::ResourceResult>
DebuggerResourceProvider::ReadDebuggerResource(llvm::StringRef uri,
lldb::user_id_t debugger_id) {
lldb::DebuggerSP debugger_sp = Debugger::FindDebuggerWithID(debugger_id);
@@ -170,17 +172,17 @@ DebuggerResourceProvider::ReadDebuggerResource(llvm::StringRef uri,
debugger_resource.name = debugger_sp->GetInstanceName();
debugger_resource.num_targets = debugger_sp->GetTargetList().GetNumTargets();
- protocol::ResourceContents contents;
+ lldb_protocol::mcp::ResourceContents contents;
contents.uri = uri;
contents.mimeType = kMimeTypeJSON;
contents.text = llvm::formatv("{0}", toJSON(debugger_resource));
- protocol::ResourceResult result;
+ lldb_protocol::mcp::ResourceResult result;
result.contents.push_back(contents);
return result;
}
-llvm::Expected<protocol::ResourceResult>
+llvm::Expected<lldb_protocol::mcp::ResourceResult>
DebuggerResourceProvider::ReadTargetResource(llvm::StringRef uri,
lldb::user_id_t debugger_id,
size_t target_idx) {
@@ -206,12 +208,12 @@ DebuggerResourceProvider::ReadTargetResource(llvm::StringRef uri,
if (lldb::PlatformSP platform_sp = target_sp->GetPlatform())
target_resource.platform = platform_sp->GetName();
- protocol::ResourceContents contents;
+ lldb_protocol::mcp::ResourceContents contents;
contents.uri = uri;
contents.mimeType = kMimeTypeJSON;
contents.text = llvm:...
[truncated]
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM!
This PR moves the MCP protocol code into its own library (
lldbProtocolMCP
) so the code can be shared between theProtocolServerMCP
plugin in LLDB as well aslldb-mcp
. The goal is to do the same thing for DAP (which, for now, would be used exclusively fromlldb-dap
).To make it clear that it's neither part of the
lldb
nor thelldb_private
namespace, I created a newlldb_protocol
namespace.Depending on how much code would be reused by lldb-dap, we may move more code into the protocol library.