anthropics / anthropics/anthropic-sdk-python

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

オープン
#1,747 コメント 2 件 リアクション 0 件 担当者 0 名 GitHub で見る
主要言語
Python
スター
3.9k
フォーク
853
平均マージ
1日 18時間
マージ済み PR(30日)
11

説明

# [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.

コントリビューションガイド

コントリビューションガイドを開く

評価

この issue はまだ評価されていません。

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。