Background Agent MCP Connections Destroyed After Text-Only Turn
- Dominant language
- Shell
- Stars
- 11.2k
- Forks
- 1.9k
- Avg merge
- 14h 16m
- Merged PRs (30d)
- 6
Description
### Describe the bug
MCP tools in background agents (launched via the `task` tool) are unreliable. The CLI framework destroys MCP transport connections after any turn where the LLM produces a text-only response (no tool calls). This means background agents that depend on MCP tools intermittently fail with `"Not connected"` or `"Connection closed"` errors - even when the MCP server is healthy and reachable.
This is a blocking issue for using custom agents with MCP servers in background mode. Any non-trivial agent workflow that involves MCP tools will eventually hit this bug because the LLM occasionally produces a text-only response before making a tool call (~10% of the time with default prompts, 100% when the system prompt encourages reasoning before acting).
The bug does not affect standalone agent invocations (`copilot --agent -p `) or the parent session's own MCP connections - only background agents.
### Affected version
GitHub Copilot CLI 1.0.35
### Steps to reproduce the behavior
### Prerequisites
- Python 3.10+ with `aiohttp` (`pip install aiohttp`)
### 1. Add the attached server
```py
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("repro-mcp-server", port=8099)
@mcp.tool()
def fast_tool(query: str) -> str:
"""Returns immediately. Echoes the query back. For testing MCP transport reliability."""
return f'{{"status": "ok", "query": "{query}"}}'
if __name__ == "__main__":
mcp.run(transport="sse")
```
Save to `~/.copilot/repro_mcp_server.py`
This is a minimal MCP SSE server that exposes a single `fast_tool` which immediately echoes back its input.
### 2. Create the agent definition
Save as `~/.copilot/agents/repro-test-agent.agent.md`:
```markdown
---
name: repro-test-agent
description: "Minimal agent for reproducing background-agent MCP bug."
mcp-servers:
repro:
type: sse
url: "http://localhost:8099/sse"
tools: ["*"]
tools: ['repro/*']
---
You are a test agent with a STRICT protocol. You MUST follow this exact sequence
for EVERY request:
Turn 1: Reply with ONLY this exact text: "Processing request." — absolutely NO
tool calls on this turn.
Turn 2: Now call the requested tool.
CRITICAL RULE: You are FORBIDDEN from calling any tool on your first turn. Your
first message MUST be pure text with zero tool calls.
```
The system prompt forces a text-only first turn. This simulates the natural LLM behaviour of reasoning before acting, which triggers the bug deterministically.
When run, the background agent produces "Processing request." on turn 1, calls `repro-fast_tool` on turn 2, and returns `{"status": "ok", "query": "test-bug"}`.
### Expected behavior
I expect that MCP tool calling is reliable for any background agent session.
### What actually happens
The agent produces text on turn 1. The framework fires internal `response` and `messages_snapshot` events which tear down the MCP transport. The agent either never gets a turn 2, or turn 2's tool call fails on a dead connection.
Debug log signature (`~/.copilot/logs/process-*.log`):
```
[DEBUG] response (Request-ID null):
[DEBUG] Ignoring event of kind: response
[DEBUG] Ignoring event of kind: messages_snapshot
[ERROR] MCP transport for repro closed
[ERROR] MCP client for repro closed
```
**Repro rate: 3/3 (100%)** with the included agent definition.
### Intermittent variant without special system prompt
The "text first" system prompt makes the bug deterministic, but it also occurs naturally. With a neutral system prompt ("call the tool and report the result"), the LLM occasionally produces text before a tool call. In testing:
- 2 failures out of ~20 background agent invocations with neutral prompts (~10%)
### Non-background agents are not affected
- `copilot --agent -p ` (standalone mode): MCP survives across turns. 0/15 failures.
- Parent session MCP tools: text-only turns do not destroy connections.
- The bug is specific to background agents spawned via the `task` tool.
### Additional context
### CLI log: standalone agent (works — MCP survives)
```
copilot --agent repro-test-agent -p 'Call repro-fast_tool with query "standalone-test".' --allow-all-tools
```
```
09:24:25.374 [ERROR] Starting remote MCP client for repro with url: http://localhost:8099/sse
09:24:25.402 [ERROR] MCP client for repro connected, took 27ms
09:24:25.533 [DEBUG] Adding tool: repro-fast_tool
09:24:27.996 [DEBUG] Making Anthropic Messages streaming request with messages: [
09:24:32.836 [DEBUG] response (Request-ID null): ← LLM response arrives
09:24:40.914 [DEBUG] Tool calls count: 2 ← includes tool_use
09:24:40.915 [DEBUG] Permission request (kind=mcp) ← tool executes
09:24:40.971 [DEBUG] Tool invocation result: {"result":"{\"status\": \"ok\", \"query\": \"standalone-test\"}"}
09:24:40.997 [DEBUG] Making Anthropic Messages streaming request ← turn 2 (report result)
09:24:43.433 [DEBUG] response (Request-ID null):
09:24:43.434 [DEBUG] Ignoring event of kind: response ← event fires...
09:24:43.434 [DEBUG] Ignoring event of kind: messages_snapshot
← but NO MCP teardown
```
### CLI log: background agent (fails — MCP destroyed)
```
copilot -p '...launch background agent...' --allow-all-tools
```
```
09:19:17.426 [INFO] Started background agent with id: bug-repro
09:19:17.486 [INFO] Custom agent "repro-test-agent" invoked
09:19:17.545 [ERROR] Starting remote MCP client for repro with url: http://localhost:8099/sse
09:19:17.573 [ERROR] MCP client for repro connected, took 27ms
09:19:17.664 [DEBUG] Adding tool: repro-fast_tool
09:19:17.666 [INFO] Found 1 MCP tools from server 'repro'
09:19:17.671 [INFO] Custom agent "repro-test-agent" using tools: repro-fast_tool, view
09:19:18.074 [DEBUG] Making Anthropic Messages streaming request ← child agent turn 1
09:19:20.632 [DEBUG] response (Request-ID null): ← text-only "Processing request."
(no "Tool calls count" line)
09:19:20.715 [INFO] System notification: Agent "bug-repro" has finished processing
← agent treated as DONE after text-only turn
...
09:19:54.619 [DEBUG] response (Request-ID null):
09:19:54.621 [DEBUG] Ignoring event of kind: response ← same event as standalone...
09:19:54.623 [DEBUG] Ignoring event of kind: messages_snapshot
09:19:54.629 [ERROR] MCP transport for repro closed ← ...but HERE it kills MCP
09:19:54.629 [ERROR] MCP client for repro closed
```
Note: both modes fire `Ignoring event of kind: response`, but only the background agent path destroys the MCP transport afterward.
Contributor guide
Research direction
Start by reproducing the issue with the provided Python SSE server and repro-test-agent.agent.md, launched through the task tool. Compare the background-agent path with standalone mode and inspect ~/.copilot/logs/process-*.log around the response and messages_snapshot events. Done means a text-only turn leaves the MCP connection usable and the following tool call succeeds.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- cli, networking
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100