When working with a MainLoop, if the file reaches the EOF it will
immediately fire the read handle callback. We cannot readily determine
if the file is at EOF or if the file is pointing to a socket/pipe that
has consumed all the current data in the buffer but the remote end has
not yet hung up. This is causing JSONTransport to continuously fire the
OnRead callback trigging repeated calls to the
`MessageHandler::OnClose`.
Since MainLoop does not perform the actual read, we need to adjust the
behavior of JSONTransport to fully own the read handle.
This change moves the ownership of the `MainLoop::ReadHandleUP` and
additionally own a reference to the `MainLoop` itself to ensure the loop
outlives the JSONTransport object.
This allows us to remove the handle immediately when we detect an EOF /
hang up has occurred.
Introducing `llvm::createStringErrorV` caused a `0.5%` compile-time
regression because it's an inline function in a core header. This moves
the API to a new header to prevent including this function in files that
don't need it.
Also includes the header in the source files that have been using
`createStringErrorV` (which currently is just LLDB).
This adds a new Binding helper class to allow mapping of incoming and
outgoing requests / events to specific handlers.
This should make it easier to create new protocol implementations and
allow us to create a relay in the lldb-mcp binary.
This fixes an issue where the MCP server would stop the main loop after
the first client disconnects.
This moves the MainLoop out of the Server instance and lifts the server
up into the ProtocolServerMCP object instead. This allows us to register
the client with the main loop used to accept and process requests.
This brings back the tool for listing debuggers.
This is helpful when an LLM doesn't support resources, like gemini-cli.
I also fixed an issue with `ServerInfoHandle` not always cleaning up the
`~/lldb/lldb-mcp-<pid>.json` file correctly.
This improves the flow by automatically connecting to an exisitng lldb
instance, if one is found.
Future improvements include:
* Launching a binary if an instance isn't detected.
* Multiplexing if multiple instances are detected.
This adjusts the ProtocolServer command to default to create a new
connection listening on `localhost:0` and adds a new `ServerMetadata`
details to `~/.lldb/mcp/lldb-<pid>.json` to record information about the
current MCP server.
This can be consumed by the lldb-mcp binary to establish a connection
from an LLM client.
---------
Co-authored-by: Jonas Devlieghere <jonas@devlieghere.com>
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.
This PR adopts JSONTransport in the MCP server implementation. It
required a slight change in design in the relationship between the two
server classes. Previously, these two had an "is-a" connection, while
now they have a "has-a" connection.
The "generic" protocol server in Protocol/MCP now operates using a
single connection (Transport). This matches the design in DAP where each
DAP instance has its own connection. The protocol server in Plugins
still supports multiple clients and creates a new server instance for
each connection.
I believe the new design makes sense in the long term (as proved by DAP)
and allows us to make the server stateful if we choose to do so. There's
no reason that multiple client support can't live in the generic
protocol library, but for now I kept it in ProtocolServerMCP to avoid
creating unnecessary abstractions.
This is a reland of #155034 but with significant changes to the tests.
The unit tests now test the generic server implementation, which matches
the original intent. This also means the test are now single threaded
and therefore fully deterministic using the MainLoop.
This PR adopts JSONTransport in the MCP server implementation. It
required a slight change in design in the relationship between the two
server classes. Previously, these two had an "is-a" connection, while
now they have a "has-a" connection.
The "generic" protocol server in Protocol/MCP now operates using a
single connection (Transport). This matches the design in DAP where each
DAP instance has its own connection. The protocol server in Plugins
still supports multiple clients and creates a new server instance for
each connection.
I believe the new design makes sense in the long term (as proved by DAP)
and allows us to make the server stateful if we choose to do so. There's
no reason that multiple client support can't live in the generic
protocol library, but for now I kept it in ProtocolServerMCP to avoid
creating unnecessary abstractions.
* This adjusts the `Request`/`Response` types to have an `id` that is
either a string or a number.
* Merges 'Error' into 'Response' to have a single response type that
represents both errors and results.
* Adjusts the `Error.data` field to by any JSON value.
* Adds `operator==` support to the base protocol types and simplifies
the tests.
This is a continuation of #152188, which started splitting up the MCP
implementation into a generic implementation in Protocol/MCP that will
be shared between LLDB and lldb-mcp.
For now I kept all the networking code in the MCP server plugin. Once
the changes to JSONTransport land, we might be able to move more of it
into the Protocol library.