anthropics / anthropics/claude-agent-sdk-typescript
query(): MCP server processes remain as zombies after session ends
- Lingua principale
- Shell
- Stelle
- 1.8k
- Fork
- 226
- Metriche di merge delle PR
- Nessuna PR unita negli ultimi 30g
Descrizione
## Bug Report
### Description
When using the Agent SDK's `query()` to orchestrate multiple sequential sessions (relay pattern), MCP server processes spawned internally by each session often survive after the session ends. This creates zombie processes that accumulate over time.
### The core problem
There is no way for an external orchestrator to determine which MCP process belongs to which session. `query()` spawns MCP servers internally, but does not:
1. Expose the spawned MCP process PIDs to the caller
2. Guarantee cleanup of MCP processes when the session ends (including timeout/error cases)
3. Provide any session-scoped tagging/grouping mechanism for spawned child processes
### Reproduction steps
1. Create a TypeScript orchestrator that calls `query()` in a loop (relay pattern)
2. Each session uses MCP servers configured in `.claude/mcp.json`
3. After each session ends (success, timeout, or error), check for remaining MCP processes
4. Observe that MCP server processes (`node.exe` for MCP Memory, `python.exe` for MCP RAG, etc.) accumulate with each session
### Workaround attempted
We use `wmic` (Windows) to snapshot all MCP-related PIDs before/after each session and kill the diff. This works for **single-mission** orchestration only. It fundamentally breaks for **concurrent missions** because:
- Before/after PID diffs cannot distinguish which mission owns which MCP process
- PID reuse (rare but real on Windows) can cause incorrect kills of unrelated processes
Since the SDK spawns MCP servers internally with no external tagging, there is no reliable way to associate MCP processes with their parent session from outside.
### Impact
After 5-10 relay sessions, dozens of zombie `node.exe` (MCP Memory server) and `python.exe` (MCP RAG server) processes accumulate, consuming memory and potentially causing port conflicts.
### Proposed solutions
Any of these would resolve the issue:
1. **`query()` guarantees MCP cleanup** on session end (including timeout/error/max_turns cases)
2. **`query()` returns spawned child PIDs** in the result message, so the orchestrator can clean them up
3. **Session-scoped process group** (e.g., Windows Job Object or Unix process group) so all child processes can be killed as a unit
4. **Option to pass existing MCP server connections** to `query()` instead of spawning new ones per session (also saves startup time)
### Environment
- **OS**: Windows 11
- **SDK**: `@anthropic-ai/claude-agent-sdk`
- **Language**: TypeScript
- **Pattern**: Relay orchestrator using `query()` in a loop with `maxTurns` per session
- **MCP servers**: Node.js (MCP Memory) + Python (MCP RAG)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Guida per i contributori
Nessuna guida per i contributori indicizzata per questo repository
Valutazione
Questa issue non è ancora stata valutata.