[lldb][lldb-mcp] `lldb-mcp` corrupts stdio JSON-RPC stream when auto-spawning backend and fails on stale session files
- Dominant language
- LLVM
- Stars
- 40.5k
- Forks
- 18.7k
- PR merge metrics
- PR metrics pending
Description
This is a verbose mostly AI generated description, TLDR is that [`lldb-mcp`](https://lldb.llvm.org/use/mcp.html) is currently broken with Antigravity and Codex (have not tried other agents).
2 issues prevent it from working out of the box:
1. **Stdio stream corruption & stdin contention**: When auto-spawning the backend LLDB instance (`$LLDB_EXE_PATH -O "protocol start MCP"`), the child process inherits `stdin`, `stdout`, and `stderr`. The child LLDB process writes interactive prompts (`(lldb) `) to `stdout` and consumes incoming JSON-RPC traffic from `stdin` as debugger commands, corrupting the MCP stream.
2. **Crash loop on stale session files**: If a previous LLDB instance crashes or is killed, `~/.lldb/lldb-mcp-.json` remains on disk. `lldb-mcp` tries to connect to the dead URI, fails with `error: failed to connect to any MCP server`, and immediately terminates rather than pruning dead sessions and spawning a new backend.
### Bug 1: Stdio Contention and Output Pollution on Auto-Spawn
When `lldb-mcp` is invoked with no running backend session:
1. It launches a child LLDB process with `$LLDB_EXE_PATH -O "protocol start MCP"`.
2. The child LLDB process inherits `lldb-mcp`'s standard I/O descriptors.
3. The interactive CLI of the child writes its greeting and interactive prompt `(lldb) ` directly to `stdout`. MCP clients expecting strict JSON-RPC (HTTP-style headers like `Content-Length: ...\r\n\r\n{...}`) fail to parse this.
4. When the MCP client sends an `initialize` JSON-RPC request to `stdin`, the child LLDB process consumes the bytes as interactive shell commands, producing errors like:
```text
error: 'Content-Length' is not a valid command
error: '{"jsonrpc":' is not a valid command
Reprod:
```python
import json
import subprocess
req = {
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2024-11-05",
"capabilities": {},
"clientInfo": {"name": "test-client", "version": "1.0"},
},
}
data = json.dumps(req)
message = f"Content-Length: {len(data)}\r\n\r\n{data}"
proc = subprocess.Popen(
["lldb-mcp"],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True,
)
stdout, stderr = proc.communicate(input=message, timeout=5)
print("--- STDOUT ---")
print(stdout)
print("--- STDERR ---")
print(stderr)
````
```log
--- STDOUT ---
(lldb) protocol start MCP
MCP server started with connection listeners: connection://[::1]:35959, connection://[127.0.0.1]:35959
(lldb) Content-Length: 166
(lldb) {"jsonrpc": "2.0", "id": 1, "method": "initialize", "params": {"protocolVersion": "2024-11-05", "capabilities": {}, "clientInfo": {"nam
--- STDERR ---
error: 'Content-Length' is not a valid command
error: '{"jsonrpc":' is not a valid command
```
### Bug 2: Unhandled Stale Session Files (`~/.lldb/lldb-mcp-*.json`)
LLDB writes session registration files containing the connection URI and PID under `~/.lldb/lldb-mcp-.json`.
If LLDB is killed (e.g. `SIGKILL`), terminates unexpectedly, or reboots:
1. `~/.lldb/lldb-mcp-.json` remains on disk.
2. The next invocation of `lldb-mcp` reads this file and attempts to connect to the stale socket.
3. The connection fails, and `lldb-mcp` exits with `error: failed to connect to any MCP server` instead of removing the stale registration and launching a new backend.
Reprod:
```bash
# 1. Create a simulated stale registration file
mkdir -p ~/.lldb
echo '{"connection_uri":"connection://[::1]:65530","pid":999999}' > ~/.lldb/lldb-mcp-999999.json
# 2. Run lldb-mcp
lldb-mcp
```
```log
error: failed to connect to any MCP server
```
Contributor guide
Research direction
Start with the lldb-mcp invocation and its auto-spawn command, `$LLDB_EXE_PATH -O "protocol start MCP"`, then trace how the child inherits standard I/O and how `~/.lldb/lldb-mcp-*.json` registrations are discovered. Reproduce both cases with the provided Python JSON-RPC client and stale-file commands; done means initialization receives an unpolluted JSON-RPC stream and a dead registration leads to a new backend.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- api, backend, cli
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100