llvm / llvm/llvm-project

[lldb][lldb-mcp] `lldb-mcp` corrupts stdio JSON-RPC stream when auto-spawning backend and fails on stale session files

Open
#223,227 1 comment 0 reactions 0 assignees View on GitHub
lldb-mcp
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

Open the contributing 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.