[BUG] Subagent teardown kills the parent session's stdio MCP server when both declare the same inline server

Status Open
Reported on v2.1.295
Maintainer reply None cached
Activity 1 comment · opened Oct 11, 2026

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report (please file separate reports for different bugs)
  • [x] I am using the latest version of Claude Code

What's Wrong?

A subagent can declare an inline stdio MCP server in its frontmatter. If that config is identical to a server the parent session already has, the subagent reuses the parent's connection. When the subagent finishes, Claude Code calls cleanup() on that connection. This sends SIGINT and then SIGTERM to the shared server process. The parent session marks the server failed and drops its tools. It doesn't reconnect until the user runs /mcp.

The most common trigger is a main-thread agent (claude --agent X) that spawns a subagent of the same type X. Both build the same config from the same agent file, so no change to the agent file can avoid the collision.

when the subagent ends, the echo MCP log (~/.cache/claude-cli-nodejs/<cwd>/mcp-logs-echo/) shows:

(see Error Messages/Logs)

/mcp shows echo as failed. The parent can't call mcp__echo__ping until you reconnect it from /mcp.

The same thing happens with two different agent files (lead as the main thread, worker as the subagent) when their inline echo definitions are identical.

What Should Happen?

the parent's echo server stays connected, and the third call succeeds.

Error Messages/Logs

From `~/.cache/claude-cli-nodejs/<cwd>/mcp-logs-echo/` when the subagent ends:


Sending SIGINT to MCP server process
MCP server process exited cleanly

Steps to Reproduce

  1. Save a minimal stdio MCP server as /tmp/echo_server.py:

```python
from mcp.server.fastmcp import FastMCP

mcp = FastMCP("echo")

@mcp.tool()
def ping() -> str:
return "pong"

mcp.run()
```

  1. Save ~/.claude/agents/lead.md:

```markdown
---
name: lead
description: Test agent that declares an inline MCP server
mcpServers:

  • echo:

command: python3
args: ["/tmp/echo_server.py"]
---
You are a test agent.
```

  1. Run claude --agent lead.
  2. Send this prompt: "Call mcp__echo__ping. Then spawn a lead subagent that calls mcp__echo__ping and returns. Then call mcp__echo__ping again."

Claude Model

Not sure / Multiple models

Is this a regression?

Yes, this worked in a previous version

Last Working Version

_No response_

Claude Code Version

2.1.295

Platform

AWS Bedrock

Operating System

Other Linux

Terminal/Shell

iTerm2

Additional Information

Root cause (from reading the 2.1.295 bundle)

  1. connectToServer is memoized in a map shared by the whole session. The key is ${name}-${hash(config)}. The hash drops scope and plugin metadata. It keeps command, args, env, and agentSource.
  2. Main-thread frontmatter servers (agentMcpSpecsToScopedConfigs) and subagent frontmatter servers both become {...config, scope: "agent", agentSource}. Two cases produce the same key, and the subagent then gets the parent's existing connection:
  • a main thread and a subagent of the same type
  • two agent files from the same source with identical inline configs
  1. Subagent MCP setup sets isNewlyCreated: true for every inline spec. String references get false. Setup doesn't check whether connectToServer returned a connection that already existed. When the subagent ends, setup calls cleanup() on every connected client marked isNewlyCreated. For stdio, cleanup() sends SIGINT and then SIGTERM to the process.
  2. The REPL onclose handler auto-reconnects only non-stdio transports (type !== "stdio" && type !== "sdk"). For stdio, it marks the client failed, which removes its tools.

Subagent tool lists put parent tools first and dedupe by name. So when the parent has the server, the subagent never calls its own connection. The teardown is its only effect.

Other trigger

Two subagents of the same type can run at the same time and both declare the server, while the parent doesn't have it. They share one connection. When the first one finishes, it kills the process during the second one's in-flight tool call.

Workaround

Give each agent file's inline server a distinct config, for example an unused env variable set to the agent name. This separates different agent types. It can't separate a main thread from a subagent of the same type, or two concurrent subagents of the same type.

Suggested fix

  • In subagent MCP setup, treat a connection as owned only if it wasn't in the connectToServer cache before the dial. Clean up only owned connections.
  • Alternatively, refcount memoized connections and close a connection on its last release.
  • Optionally, have the REPL onclose handler re-dial a stdio server that another owner's cleanup() closed, instead of marking it failed.

Related

  • #84638 reports the same content-keyed sharing between concurrent subagents with byte-identical inline configs. That report covers the loss of isolation. This one covers the teardown: the shared connection belongs to the main session too, and the subagent kills it. #84638 was closed as stale on 2026-10-05. The behavior is still present in 2.1.295.
  • #86040 reports the teardown symptom. Claude Code sends SIGINT and SIGTERM to a healthy stdio server, and a background Agent task stops at the same second. It was closed as stale without a root cause. This may be the cause.

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗