#MCP server processes not being reaped after agent sessions end

1 messages · Page 1 of 1 (latest)

mossy shore
#

Hi Krill,
I'm seeing memory accumulate in my container over time. After diagnostics, I found that npm exec MCP server processes (context7, sqlite, filesystem) are not being killed after their parent agent session completes. Each process holds ~96–100MB RSS, and they stack up across cron-triggered runs — I'm counting ~150 processes in ps aux, eating ~2–3GB of my 6GB container RAM limit.
My MCP config in openclaw.json:
json"mcp": {
"servers": {
"filesystem": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/home/node/.openclaw/workspace"]
},
"context7": {
"command": "npx",
"args": ["-y", "@upstash/context7-mcp"]
},
"sqlite": {
"command": "npx",
"args": ["-y", "mcp-server-sqlite-npx", "/home/node/.openclaw/workspace/projects/health-fitness/data/health.db"]
}
}
}
Running v2026.4.15, hub-and-spoke agents with maxSpawnDepth:2, cron-triggered sessions via sessions_spawn.
Questions:

Should MCP servers exit when their spawned session ends, or are they intentionally kept alive for reuse?
If they should be reaped, is this a known bug or a config I'm missing?
Is there a safe way to clean up stale MCP child processes without a full container restart?

solemn anchorBOT
burnt reefBOT
#

To help others find answers, you can mark your question as solved via Right click solution message -> Apps -> âś… Mark Solution

jovial krakenBOT
#

Let me trace the spawned-run cleanup path all the way through before I answer, so I don’t guess.

#

I traced the code, and there are two separate behaviors here.

  1. sessions_spawn defaults to run mode + cleanup: "keep" unless you override it.
    So for cron-spawned one-shot children, the child session is kept after the run finishes, and because bundled MCP runtimes are session-scoped, those npx MCP processes stay alive with that session.

  2. There also looks like a real cleanup gap in v2026.4.15.
    I found explicit disposeSessionMcpRuntime(...) on session reset and on local one-shot runs, but I do not see that disposal happening in the gateway sessions.delete path. So if you already use cleanup: "delete" and still see the MCP children pile up, I’d treat that as a bug, not a missing config.

So my answer would be:

  • Should they exit?
    If the spawned session is being kept, no, keeping them alive is currently consistent with the session-scoped design.
    If the spawned session is deleted, they should be reaped, and that looks incomplete right now.

  • Missing config or bug?
    If you did not set cleanup: "delete", start there.
    If you did set it, this looks like a bug.

#
  • Safe cleanup without full container restart?
    The safest supported option I can recommend right now is:
    openclaw gateway restart
    That should clear the in-memory session runtime state without restarting the whole container.

For your cron/hub-and-spoke runs, I’d change the spawn call to something like:

{ runtime: "subagent", mode: "run", cleanup: "delete", ... }

If you’re already doing that, please file it here with your repro, this looks worth maintainer attention: https://github.com/openclaw/openclaw/issues

If you want, paste the exact sessions_spawn payload you’re using and I’ll sanity check it.

mossy shore
#

Krill, we traced the source and found the exact flag: cleanupBundleMcpOnRunEnd in pi-embedded-runner/run.ts defaults to false. That confirms your diagnosis.
Quick clarification before I change anything: does setting cleanup: "delete" in the sessions_spawn payload also set cleanupBundleMcpOnRunEnd: true internally, or do these need to be set independently?

jovial krakenBOT
#

No, they’re independent right now.

From the source:

  • cleanup: "delete" on sessions_spawn controls child session cleanup after the spawned run finishes.
  • cleanupBundleMcpOnRunEnd controls bundle MCP runtime disposal at end of the run.

I do not see sessions_spawn wiring cleanup: "delete" into cleanupBundleMcpOnRunEnd: true internally.

In fact, the only explicit non-test wiring I found for cleanupBundleMcpOnRunEnd was the local one-shot path in src/commands/agent-via-gateway.ts, where it’s set from opts.local === true. I don’t see an equivalent hookup in the sessions_spawn path.

So the practical answer is:

  • cleanup: "delete" does not currently imply cleanupBundleMcpOnRunEnd: true
  • and I don’t think sessions_spawn exposes a way to set that flag directly today

So yes, this still looks like a cleanup gap for spawned runs in v2026.4.15.