[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