[Lldb-commits] [lldb] 7850239 - [lldb][docs] Rewrite the MCP documentation for lldb-mcp (#212821)
via lldb-commits
lldb-commits at lists.llvm.org
Thu Jul 30 09:11:19 PDT 2026
Author: Jonas Devlieghere
Date: 2026-07-30T09:11:14-07:00
New Revision: 7850239749970847955a918d731630b35c540af2
URL: https://github.com/llvm/llvm-project/commit/7850239749970847955a918d731630b35c540af2
DIFF: https://github.com/llvm/llvm-project/commit/7850239749970847955a918d731630b35c540af2.diff
LOG: [lldb][docs] Rewrite the MCP documentation for lldb-mcp (#212821)
The docs still describe lldb-mcp as a thin stdio-to-socket bridge that
auto-launches an LLDB and exposes a single lldb_command tool. It is now
a full featured multiplexer hosting its own sessions, with four tools
and pid-qualified URIs. Also restructure the documentation around how it
is used, with an explanation of the underlying architecture towards the
end.
Added:
Modified:
lldb/docs/use/mcp.md
Removed:
################################################################################
diff --git a/lldb/docs/use/mcp.md b/lldb/docs/use/mcp.md
index 452a6e4d2fabb..2580e9d283ea0 100644
--- a/lldb/docs/use/mcp.md
+++ b/lldb/docs/use/mcp.md
@@ -8,89 +8,154 @@ memory, step through code. This can range from helping you run a specific
command you cannot immediately remember, to a fully agent-driven debugging
experience.
-## MCP Server
+## Getting Started
-To start the MCP server in LLDB, use the `protocol-server start` command.
-Specify `MCP` as the protocol and provide a URI to listen on. For example, to
-start listening for local TCP connections on port `59999`, use the following
-command:
+LLDB ships with `lldb-mcp`, a binary that speaks MCP over standard input and
+output (stdio). Point your MCP client at it, and you are all set.
+
+Configuration example for [Claude Code](https://modelcontextprotocol.io/quickstart/user):
```
-(lldb) protocol-server start MCP listen://localhost:59999
-MCP server started with connection listeners: connection://[::1]:59999, connection://[127.0.0.1]:59999
+claude mcp add lldb --transport stdio -- /path/to/lldb-mcp
```
-The server will automatically stop when exiting LLDB, or it can be stopped
-explicitly with the `protocol-server stop` command.
+Configuration example (`mcp.json`) for [Visual Studio Code](https://code.visualstudio.com/docs/copilot/chat/mcp-servers):
+```json
+{
+ "servers": {
+ "lldb": {
+ "type": "stdio",
+ "command": "/path/to/lldb-mcp"
+ }
+ }
+}
```
-(lldb) protocol-server stop MCP
+
+The MCP client launches one `lldb-mcp` process per connection and shuts it down
+when it disconnects, taking any session it created with it.
+
+## Tools
+
+Tools are a primitive in the Model Context Protocol that enable servers to
+expose functionality to clients. `lldb-mcp` exposes four.
+
+### `session_create`
+
+Creates a new debug session and returns its URI. This is equivalent to
+launching a new instance of `lldb` on the command line. Sessions look like
+this:
+
+```
+lldb-mcp://instance/{pid}/debugger/{id}
```
-The commands will fail if a server is already running or not running
-respectively.
+The `pid` identifies the process hosting the session and the `id` identifies
+the debugger inside it. Pass the whole URI back to the other tools.
+
+### `command`
+
+Runs an LLDB command in a debug session and returns its output, the same text
+you would see in the LLDB command interpreter. It takes:
-## MCP Client
+- `command` (required): the command to run, for example `breakpoint set --name main`.
+- `debugger` (optional): the URI of the session to run it in. When omitted, the
+ command runs in the first session `lldb-mcp` created.
-MCP uses standard input/output (stdio) for communication between client and
-server. The exact configuration depends on the client, but most applications
-allow you to specify an MCP server as a binary and arguments. LLDB ships with
-`lldb-mcp`, a small helper that bridges stdio to LLDB's MCP server socket.
+Commands run one at a time and the result comes back when the command finishes.
+
+### `sessions_list`
+
+Lists every debug session reachable from this `lldb-mcp`, one URI per line.
+That includes sessions it created itself and sessions in LLDB instances running
+elsewhere on the machine (see [Attaching to a Running LLDB](#attaching-to-a-running-lldb)).
+
+### `session_close`
+
+Closes a session and frees its resources. It takes a single required `session`
+argument, the URI to close. Only sessions that `lldb-mcp` created can be closed
+this way. An interactive LLDB that a person is using belongs to that person, so
+closing it is refused.
+
+## A Typical Session
+
+Creating a session, debugging in it, and cleaning up looks like this:
```
-┌──────────┐ ┌──────────┐ ┌──────────┐
-│ │ │ │ │ │
-│ LLDB ├─────socket────┤ lldb-mcp ├─────stdio─────┤MCP Client│
-│ │ │ │ │ │
-└──────────┘ └──────────┘ └──────────┘
+session_create -> lldb-mcp://instance/4711/debugger/1
+command "target create /tmp/hello" -> Current executable set to '/tmp/hello' (arm64).
+command "breakpoint set --name add" -> Breakpoint 1: 4 locations.
+command "run" -> Process 4713 stopped
+ * thread #1, stop reason = breakpoint 1.1
+ frame #0: hello`add(a=2, b=3) at hello.c:2
+command "frame variable" -> (int) a = 2
+ (int) b = 3
+command "continue" -> Process 4713 exited with status = 0
+session_close -> deleted lldb-mcp://debugger/1
```
-`lldb-mcp` automatically discovers a running LLDB MCP server, so there is no
-need to specify a port. If no server is running, it will launch `lldb` in the
-background and connect to it. The `lldb` binary located next to `lldb-mcp` is
-used by default; set the `LLDB_EXE_PATH` environment variable to override this.
+:::{note}
+Sessions start in asynchronous mode, where `run` and `continue` return before
+the process actually stops. Commands that need a stopped process then fail with
+"Command requires a process which is currently stopped". Run
+`script lldb.debugger.SetAsync(False)` once, right after `session_create`, to
+get the synchronous behavior shown above.
+:::
-Configuration example for [Claude Code](https://modelcontextprotocol.io/quickstart/user):
+The debuggee's own output does not come back through MCP. Only debugger output
+does. Redirect the program's output to a file and read it back if you need it.
+
+## Attaching to a Running LLDB
+
+Besides the sessions it creates, `lldb-mcp` can drive LLDB instances you are
+already using, so an agent can inspect and steer the exact session you have in
+front of you.
+
+In that LLDB, start an MCP server:
```
-claude mcp add --transport stdio -- lldb-mcp /path/to/lldb-mcp
+(lldb) protocol-server start MCP
+MCP server started with connection listeners: connection://[::1]:59999, connection://[127.0.0.1]:59999
```
-Configuration example (`mcp.json`) for [Visual Studio Code](https://code.visualstudio.com/docs/copilot/chat/mcp-servers):
+The server picks a free port on localhost by default. To listen somewhere
+specific, pass a URI, either `listen://[host]:port` for TCP or
+`accept:///path/to/socket` for a Unix domain socket:
-```json
-{
- "servers": {
- "lldb": {
- "type": "stdio",
- "command": "/path/to/lldb-mcp"
- }
- }
-}
+```
+(lldb) protocol-server start MCP listen://localhost:59999
```
-## Tools
+The server stops when LLDB exits, or explicitly:
-Tools are a primitive in the Model Context Protocol that enable servers to
-expose functionality to clients.
+```
+(lldb) protocol-server stop MCP
+```
+
+`protocol-server get MCP` reports where a running server is listening. Starting
+a server when one is already running, or stopping one that is not, is an error.
-LLDB's MCP integration exposes one tool, named `lldb_command` which allows the
-model to run the same commands a user would type in the LLDB command
-interpreter. It takes two arguments:
+Once the server is up, that LLDB's sessions show up in `sessions_list` and
+accept `command`, exactly like sessions `lldb-mcp` created. You do not need to
+configure a port anywhere: each LLDB with a running MCP server records itself in
+`~/.lldb`, and `lldb-mcp` finds it there.
-1. The unique debugger ID as a number.
-2. The command and its arguments as a string.
+:::{note}
+Discovery happens once, when `lldb-mcp` starts. An LLDB you launch afterwards is
+not picked up until the client reconnects to the MCP server, which usually means
+restarting or reloading the MCP server in your client.
+:::
## Resources
Resources are a primitive in the Model Context Protocol that allow servers to
-expose content that can be read by clients.
+expose content that can be read by clients. `lldb-mcp` exposes one resource per
+debugger and one per target, across every session it can reach.
-LLDB's MCP integration exposes a resource for each debugger and target
-instance. Debugger resources are accessible using the following URI:
+Debugger resources use the following URI:
```
-lldb://debugger/<debugger id>
+lldb://instance/<pid>/debugger/<debugger id>
```
Example output:
@@ -99,7 +164,7 @@ Example output:
{
"contents": [
{
- "uri": "lldb://debugger/1",
+ "uri": "lldb://instance/4711/debugger/1",
"mimeType": "application/json",
"text": "{\"debugger_id\":1,\"name\":\"debugger_1\",\"num_targets\":1}"
}
@@ -111,7 +176,7 @@ Debuggers can contain one or more targets, which are accessible using the
following URI:
```
-lldb://debugger/<debugger id>/target/<target idx>
+lldb://instance/<pid>/debugger/<debugger id>/target/<target idx>
```
Example output:
@@ -120,9 +185,9 @@ Example output:
{
"contents": [
{
- "uri": "lldb://debugger/1/target/0",
+ "uri": "lldb://instance/4711/debugger/1/target/0",
"mimeType": "application/json",
- "text": "{\"arch\":\"arm64-apple-macosx26.0.0\",\"debugger_id\":1,\"dummy\":false,\"path\":\"/bin/count\",\"platform\":\"host\",\"selected\":true,\"target_idx\":0}"
+ "text": "{\"arch\":\"arm64-apple-macosx26.0.0\",\"debugger_id\":1,\"dummy\":false,\"path\":\"/tmp/hello\",\"platform\":\"host\",\"selected\":true,\"target_idx\":0}"
}
]
}
@@ -133,9 +198,102 @@ stable and may be reused when a target is removed and a new target is added.
## Troubleshooting
-The MCP server uses the `Host` log channel. You can enable logging with the
-`log enable` command.
+**"no debugger found" from `command`.** There is no session to run the command
+in. Call `session_create` first, or pass the URI of an existing session.
+
+**"Command requires a process which is currently stopped".** The session is in
+asynchronous mode. Run `script lldb.debugger.SetAsync(False)` in it.
+
+**"can only close sessions that lldb-mcp created".** `session_close` refuses to
+tear down an interactive LLDB. Quit that LLDB yourself.
+
+**A running LLDB does not show up in `sessions_list`.** Either its MCP server is
+not running, which `protocol-server get MCP` will tell you, or it started after
+`lldb-mcp` did. Restart the MCP server in your client to rediscover.
+
+To see the JSON-RPC traffic between your client and `lldb-mcp`, set
+`LLDB_MCP_LOG` in the environment. Messages are written to stderr, since stdout
+carries the protocol.
+
+The MCP server inside LLDB logs to the `Host` log channel:
```
(lldb) log enable lldb host
```
+
+## Implementation
+
+This section covers how the pieces fit together, for those working on LLDB
+itself.
+
+`lldb-mcp` is a multiplexer. It presents a single MCP server to the client and
+fans out to one or more backends, each an LLDB MCP server reached over a socket
+and identified by the pid of the process hosting it.
+
+```
+ ┌──────────┐
+ │ LLDB │
+ └────┬─────┘
+ │ socket
+ │
+┌──────────┐ ┌─────┴─────┐ ┌──────────┐
+│ in-proc ├────socket────┤ lldb-mcp ├─────stdio────┤MCP Client│
+│ LLDB │ └─────┬─────┘ └──────────┘
+└──────────┘ │ socket
+ │
+ ┌────┴─────┐
+ │ LLDB │
+ └──────────┘
+```
+
+There are two kinds of backend. The **local** backend is an MCP server that
+`lldb-mcp` starts inside its own process, through `SBProtocolServer`. The
+sessions it hosts are the ones `session_create` makes. **Remote** backends are
+the separate LLDB processes discovered through the registry. Both are driven the
+same way, over a socket through an `mcp::Client`, which keeps the tool
+implementations in one place rather than special-casing the in-process path.
+
+Requests are dispatched three ways. `initialize` and `tools/list` are answered
+by the multiplexer directly. `sessions_list` and `resources/list` fan out to
+every live backend and aggregate, keyed by pid so output is deterministic. A
+backend that fails or has disconnected is omitted rather than failing the whole
+listing. `command`, `resources/read`, and `session_close` are routed to a single
+backend by the pid parsed out of the URI.
+
+Backends only know their own local `lldb-mcp://debugger/{id}` and
+`lldb://debugger/{id}` URIs. The multiplexer rewrites them into the
+instance-qualified form in both directions, so a client never sees an ambiguous
+id and a backend never sees a pid it does not understand.
+
+`session_create` and `session_close` map onto the `debugger_create` and
+`debugger_delete` tools on the local backend. Session ownership is enforced by
+comparing the pid in the URI against the local backend's, which is why closing
+someone else's session is refused. Running a command in one is not: any
+`lldb-mcp` on the machine can drive any discovered session.
+
+### Discovery
+
+An LLDB that starts an MCP server writes `~/.lldb/lldb-mcp-<pid>.json`,
+recording the pid and the URI to connect to. The entry is written only once the
+server is listening, and removed on a clean exit. `lldb-mcp` reads the directory
+at startup and connects to each entry, pruning any that fails to connect, since
+that means the instance died without cleaning up. `lldb-mcp` registers itself
+too, so its managed sessions are visible to other `lldb-mcp` processes.
+
+### Adding Tools and Resources
+
+The tool and resource-provider set lives in
+`lldb/source/Plugins/Protocol/MCP/` and is installed by
+`lldb_private::mcp::PopulateServer`. Sharing one installer keeps every MCP
+server consistent, whether it runs in the plugin or is hosted in-process by an
+embedder. Adding a tool means subclassing `lldb_protocol::mcp::Tool`, and adding
+a resource means subclassing `lldb_protocol::mcp::ResourceProvider`, then
+registering it there.
+
+A tool added this way is exposed by the LLDB MCP server, not automatically by
+`lldb-mcp`. Because the multiplexer owns the client-facing surface, it also
+needs a case in `HandleToolsList` and `HandleToolsCall`, plus a routing decision
+if its arguments carry a URI.
+
+Note that the protocol version LLDB implements is `2024-11-05`, which has no
+structured content. Tools return their output as text.
More information about the lldb-commits
mailing list