devenv mcp holds ~4 GiB per process for the lifetime of the process, and ignores SIGTERM
Running devenv mcp as a long-lived MCP server, each server process settles at roughly 4 GiB of allocated memory and holds it until the process exits. Because the server is spawned per client session, this accumulates across sessions. On a 15 GiB laptop it exhausted memory and led to an OOM kill that took down unrelated work.
Measurements
Three separate processes on the same machine:
| Process | RSS | VmSwap | Uptime |
|---|---|---|---|
| A | — | 4.3 GiB | ~2 h |
| B | 644 KiB | 4.2 GiB | ~8 h |
| C | 596 KiB | 4.1 GiB | ~8 h |
Two details seem worth pointing out.
Resident size is misleading. B and C showed well under a megabyte resident while holding gigabytes in swap. Anyone checking with ps and looking at RSS will conclude the process is idle and tiny. The allocation only shows up in VmSwap (or smaps_rollup).
The three figures land within 5% of each other despite different uptimes and different sessions. That looks more like a fixed initialisation cost than growth proportional to work performed.
No tool on these servers was ever invoked
As far as I can determine, nothing ever called search_options, search_packages, or any other tool on any of these processes. They were spawned when an MCP client opened a session and then sat unused.
If that is right, the allocation is triggered by the connection handshake itself — initialize, or the initial tools/list — rather than by any request for the server's functionality. That would make the reproduction simply: connect any MCP client to devenv mcp, call nothing, and measure the process.
It also changes who pays the cost. It is not paid by people using devenv's search tools; it is paid by everyone who has the server configured at all, whether or not they ever touch it.
How it accumulates
The MCP server was configured at user scope in the client, so it starts for every session in every project:
"devenv": { "command": "devenv", "args": ["mcp"] }No arguments, no working directory. Working across several isolated devenv environments meant several concurrent client sessions, and therefore several concurrent devenv mcp processes, each holding its own ~4 GiB. Two left over from earlier work plus one starting was enough to run the machine out of memory.
Note that the invocation is a bare devenv mcp in whatever directory the client happens to start in — including directories with no devenv at all, which may itself be informative about when the allocation happens.
SIGTERM is ignored
All three processes ignored SIGTERM and required SIGKILL after a 5-second grace period. This matters independently of the memory: a process that cannot be asked to exit cannot be cleanly recycled by a supervisor or by a session-teardown path.
Killing two of them dropped system swap usage from 14 GiB to 7 GiB immediately.
What I have not established
I have not measured RSS at startup before any request, so I cannot confirm whether the allocation happens at process start or during the client handshake. I stopped short of testing that because reproducing it costs another ~4 GiB on a machine that had already been OOM-killed once.
Environment
- devenv 2.1.2 (x86_64-linux)
- Nix 2.31.3
- Ubuntu 24.04.4 LTS, kernel 6.8.0-136-generic
Source: cachix/devenv