Description
When the LSP server process spawned by mcpls (e.g. rust-analyzer) dies mid-session — killed externally, OOM, or a segfault — mcpls surfaces a clean, well-formed error on the in-flight and all subsequent tool calls for that language, but never attempts to restart/respawn the server. The session remains permanently degraded for that language until the entire mcpls process is restarted by the client.
Grepped the codebase for restart/respawn/supervision logic: none exists. The only reference is a forward-looking comment at crates/mcpls-core/src/bridge/translator.rs:170-171 ("during background init, so this can't race a restart. If server restart/supervision is ever added, ...") confirming this was never implemented.
This matters for any long-running AI agent session — a single rust-analyzer crash (which does happen under memory pressure or on malformed workspace state) silently and permanently removes all LSP-backed tools for that language, with no recovery path other than the client noticing and restarting the whole mcpls process.
Reproduction Steps
- Start mcpls with a single-language config (e.g. rust-analyzer).
- Initialize and confirm a tool call works, e.g.
get_hover returns real hover info.
- Kill only the rust-analyzer child process spawned by mcpls (not mcpls itself):
pgrep -P <mcpls_pid> to find it, then kill -9 <pid>.
- Immediately call
get_hover again — returns {"error":{"code":-32603,"message":"LSP server process terminated unexpectedly"}}.
- Wait 8+ seconds and call
get_hover again — same error, indefinitely. No respawn attempt observed.
Expected Behavior
At minimum, one of:
- mcpls detects the dead child process and respawns/re-initializes it on the next tool call for that language (transparent recovery), or
- if auto-restart is an intentional non-goal, the error message should say so explicitly (e.g. "language server died and will not be restarted; restart mcpls to recover") rather than implying a possibly-transient per-call failure.
Actual Behavior
Silent, permanent, unrecoverable failure for that language's tools, with an error message ("terminated unexpectedly") that reads as if a retry might succeed, when no retry ever will.
Environment
- Version: mcpls 0.3.7, commit 2c8ad7f (HEAD as of this cycle, no commits since)
- Config: single rust-analyzer server,
.local/testing/scratch/cfg_single_rust.toml
- Features: default
Logs / Evidence
Live-tested via MCP stdio JSON-RPC harness (.local/testing/scratch/test_concurrent_and_crash.py, Scenario B):
pre-check: hover succeeds, returns Translator struct doc
[kill -9 on the rust-analyzer child PID only]
+3s: {"error":{"code":-32603,"message":"LSP server process terminated unexpectedly"}}
+11s: {"error":{"code":-32603,"message":"LSP server process terminated unexpectedly"}} (same, no recovery)
Note: the kill targeted only the specific rust-analyzer child of the test's own mcpls process (verified via pgrep -P <mcpls_pid>), not a blanket pkill -f rust-analyzer, to avoid disturbing unrelated rust-analyzer instances on the same machine.
Description
When the LSP server process spawned by mcpls (e.g.
rust-analyzer) dies mid-session — killed externally, OOM, or a segfault — mcpls surfaces a clean, well-formed error on the in-flight and all subsequent tool calls for that language, but never attempts to restart/respawn the server. The session remains permanently degraded for that language until the entire mcpls process is restarted by the client.Grepped the codebase for restart/respawn/supervision logic: none exists. The only reference is a forward-looking comment at
crates/mcpls-core/src/bridge/translator.rs:170-171("during background init, so this can't race a restart. If server restart/supervision is ever added, ...") confirming this was never implemented.This matters for any long-running AI agent session — a single rust-analyzer crash (which does happen under memory pressure or on malformed workspace state) silently and permanently removes all LSP-backed tools for that language, with no recovery path other than the client noticing and restarting the whole mcpls process.
Reproduction Steps
get_hoverreturns real hover info.pgrep -P <mcpls_pid>to find it, thenkill -9 <pid>.get_hoveragain — returns{"error":{"code":-32603,"message":"LSP server process terminated unexpectedly"}}.get_hoveragain — same error, indefinitely. No respawn attempt observed.Expected Behavior
At minimum, one of:
Actual Behavior
Silent, permanent, unrecoverable failure for that language's tools, with an error message ("terminated unexpectedly") that reads as if a retry might succeed, when no retry ever will.
Environment
.local/testing/scratch/cfg_single_rust.tomlLogs / Evidence
Live-tested via MCP stdio JSON-RPC harness (
.local/testing/scratch/test_concurrent_and_crash.py, Scenario B):Note: the kill targeted only the specific rust-analyzer child of the test's own mcpls process (verified via
pgrep -P <mcpls_pid>), not a blanketpkill -f rust-analyzer, to avoid disturbing unrelated rust-analyzer instances on the same machine.