anthropics / anthropics/anthropic-sdk-python

[BUG] MCP connector: parallel mcp_tool_use calls stall ~300s per turn; one call per batch runs twice

Abierto
#1,747 2 comentarios 0 reacciones 0 asignados Ver en GitHub
Lenguaje dominante
Python
Estrellas
3.9k
Forks
853
Merge medio
1 d 18 h
PR fusionados (30 d)
11

Descripción

# [BUG] MCP connector (`mcp-client-2025-11-20`): turns with multiple parallel `mcp_tool_use` calls stall ~300s at the turn boundary; one call per batch is executed twice

## Summary

When using the server-side MCP connector on the Messages API (beta `mcp-client-2025-11-20`) in a streaming agentic loop, any assistant turn that emits **more than one `mcp_tool_use` block in parallel** is followed by a **~300-second stall** before the tool results / next turn arrive on the stream — even though the MCP server completed every call in under a second. Turns that emit a **single** `mcp_tool_use` call continue promptly (a few seconds).

Additionally, in every multi-call batch we observed **exactly one of the calls being executed twice** by the connector (two identical requests to the MCP backend within the same second).

The stall is model-independent (reproduced on `claude-sonnet-4-6` and `claude-opus-4-8`) and made our report-generation runs take 38–45 minutes instead of ~7.

## Environment

- SDK: `anthropic` **0.116.0** (Python 3.13), `client.beta.messages.stream(...)` + `get_final_message()`
- Betas: `mcp-client-2025-11-20`, `skills-2025-10-02`, `files-api-2025-04-14`
- Models: `claude-sonnet-4-6` and `claude-opus-4-8` (both affected)
- MCP server: Google BigQuery MCP (`https://bigquery.googleapis.com/mcp`, `type: "url"`, OAuth `authorization_token`)
- Tools: `mcp_toolset` (restricted via `default_config: {enabled: false}` + `configs: {execute_sql_readonly: {enabled: true}}`) + `code_execution_20250825`; `container.skills` includes the `pdf` skill and custom skills
- `thinking: {type: "disabled"}`, `max_tokens: 32000`, request `timeout: 1800`

## Request shape (abridged)

```python
client.beta.messages.stream(
model="claude-sonnet-4-6",
max_tokens=32000,
system=[...],
messages=[{"role": "user", "content": ""}],
mcp_servers=[{
"type": "url",
"url": "https://bigquery.googleapis.com/mcp",
"name": "bigquery",
"authorization_token": "",
}],
tools=[
{
"type": "mcp_toolset",
"mcp_server_name": "bigquery",
"default_config": {"enabled": False},
"configs": {"execute_sql_readonly": {"enabled": True}},
},
{"type": "code_execution_20250825", "name": "code_execution"},
],
container={"skills": [...]},
thinking={"type": "disabled"},
betas=["mcp-client-2025-11-20", "skills-2025-10-02", "files-api-2025-04-14"],
timeout=1800,
)
```

## Evidence

We instrumented the SSE stream (per-event timing) **and** correlated with BigQuery's
`INFORMATION_SCHEMA.JOBS_BY_PROJECT` (the MCP server labels its jobs `goog-mcp-server: true`,
so every connector-issued query is visible with exact timings).

**1. Tool executions are instant; the stall is between turns.** In a 38-minute run
(24 MCP calls, 2026-07-08, UTC), BigQuery job records show every query completed with
`queued_s=0, run_s=0` (17–500 slot-ms, 8–45 MB scanned). Yet the stream showed
`wait after mcp_tool_use ≈ 1811s` total, arriving as ~301s gaps.

**2. Job creation timestamps arrive in bursts spaced ~311s apart.** The model emitted
3–4 parallel `mcp_tool_use` blocks per turn; all jobs in the burst ran instantly at the
same second, then *nothing* for ~300s before the next burst:

```
12:52:33 (4 jobs) ← all complete in <1s
12:57:50 (4 jobs) ← +317s
13:03:02 (4 jobs) ← +312s
13:08:15 (4 jobs) ← +313s
13:13:26 (3 jobs) ← +311s
13:18:38 (3 jobs) ← +312s
13:23:45 (2 jobs) ← +307s
```

**3. Single-call turns do NOT stall.** In an Opus run the one turn that issued a single
`mcp_tool_use` was followed by the next call just **15s** later, while every multi-call
turn was followed by a ~310s gap. A separate run whose turns were all single-call had
**zero** stalls (total MCP wait 4.9s across 18 sequential calls).

**4. Duplicate execution.** In every multi-call burst, exactly one query appears **twice**
in the BigQuery job log — identical SQL, same creation second — i.e. the connector executed
one of the batched calls twice.

**5. Workaround confirms the trigger.** Setting
`tool_choice={"type": "auto", "disable_parallel_tool_use": True}` (forcing one MCP call
per turn) eliminates the stalls completely: the same report went from **2278s to 425s**,
with `slowest per-call wait = 3.2s` (was 301.9s).

The ~301s uniformity (301.0–303.0 across runs and models) strongly suggests a fixed
~300s timeout being waited out server-side in the connector's parallel-execution path.

Possibly related: during the long stalls we also occasionally saw the SSE stream drop
mid-response (`httpx.RemoteProtocolError: peer closed connection without sending complete
message body (incomplete chunked read)`), forcing a full restart of the request.

## Expected behavior

Parallel `mcp_tool_use` calls should return their `mcp_tool_result`s as soon as the MCP
server responds (sub-second here), matching the behavior of single-call turns — and each
call should be executed exactly once.

## Impact

Each multi-call turn costs a flat ~5 minutes. A typical analytics-agent run with 6–7
multi-call turns takes 35–45 minutes instead of ~7, and the long idle stream is prone to
mid-stream drops. `disable_parallel_tool_use` works around it at the cost of sequential
tool latency.

## Timestamps for tracing

- Affected runs (UTC, 2026-07-08): ~12:52–13:30 (`claude-sonnet-4-6`) and ~14:52–15:17 (`claude-opus-4-8`)
- Workaround run (no stalls): 2026-07-08 ~17:13–17:20 UTC
- Request IDs: available on request — happy to re-run a repro with parallel tool use re-enabled and attach the `request-id`s.

Guía de contribución

Abrir la guía de contribución

Evaluación

Este issue todavía no se ha evaluado.

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.