anthropics / anthropics/claude-code

[BUG] Custom MCP connector: tool calls dropped before reaching origin — Claude Code, claude.ai Chat and Cowork

オープン
#93,956 コメント 0 件 リアクション 0 件 担当者 0 名 GitHub で見る
area:cowork area:mcp bug
主要言語
Python
スター
145k
フォーク
23.1k
PR マージ指標
PR 指標を取得中

説明

### Preflight Checklist

- [x] I have searched [existing issues](https://github.com/anthropics/claude-code/issues?q=is%3Aissue%20state%3Aopen%20label%3Abug) 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?

Tool calls to a **custom self-hosted remote MCP connector** are intermittently dropped before reaching the origin server. The client reports an error blaming my infrastructure; the origin's access logs prove no request ever arrived.

Observed on **three separate surfaces**, same account, same connector, same day:

- **Claude Code** (desktop app, on my own Windows machine) — `This connector's server hostname doesn't resolve or isn't reachable from this network.`
- **claude.ai Chat** — same message, and usefully it carries a **`request_id`**:
`{"error": "This connector's server hostname doesn't resolve or isn't reachable from this network. The connector may be misconfigured.", "request_id": "req_011CezoxwxEMbE9gCwJv9e5u"}`
- **Claude Cowork** (cloud-hosted on Anthropic infrastructure, not local) — Cloudflare 502 carrying `"zone":"api.anthropic.com"` and `"error_category":"origin"`.

That spread matters: my local network, DNS and machine cannot account for failures originating from cloud Cowork and from claude.ai, and a client-side defect would have to exist independently in three unrelated clients.

**Measured rate: 2 drops in 62 calls (~3%)** across six batches. The two clearest instances:

- Claude Code, 6 concurrent calls — 5 arrived at origin (`200 OK`), **1 never arrived**
- claude.ai Chat, 18 **sequential** calls — 17 arrived (`200 OK`), **1 never arrived** (`03_voice`), with the `request_id` above

The second is important twice over: that batch was dispatched sequentially, one call per turn-step, so **concurrency is not required**; and re-running the identical 18-path request immediately afterwards returned 18/18, including the exact path that had failed — so it is not path-, payload- or content-dependent either.

The origin was healthy throughout — 0 errors, 0 restarts, and **zero 5xx responses in its entire access log history**. It has never returned a 502 to anything.

**Origin setup:** self-hosted Python MCP server (`mcp` SDK / FastMCP), Streamable HTTP, `json_response=True`, behind a Caddy reverse proxy, MCP-native OAuth + bearer token. Seven such services on the same host behind the same proxy and auth.

**Already ruled out — origin-side session state.** Suspecting the client and origin were disagreeing about session identity, I switched the server from `stateless_http=False` to `stateless_http=True`, so there is no in-memory session to lose and no `Mcp-Session-Id` to go stale. The symptom persisted unchanged.

### What Should Happen?

Tool calls to a custom remote MCP connector should reach the origin — or, when they cannot, fail with an error that names the actual failure.

Specifically:

1. **Tool calls should not be silently dropped in transit.** Two vanished out of 44, on two different surfaces, one of them from a purely sequential batch. The origin never saw either.

2. **A delivery failure should not be reported as an origin failure.** "This connector's server hostname doesn't resolve or isn't reachable from this network" is actively misleading: at the moment it was shown, the hostname resolved on public DNS, the host was reachable, and it was returning `200 OK` to Anthropic's own egress addresses immediately before and after — in the 18-call batch, on the calls either side of the one that failed. That message cost me roughly a day investigating DNS, tunnel config, reverse-proxy routing and service health before the origin's access logs showed nothing was arriving at all.

3. **Likewise the 502 should not carry `"error_category":"origin"`** when the origin received no request.

4. **Surface the `request_id` consistently.** claude.ai Chat returns one with this error — `req_011CezoxwxEMbE9gCwJv9e5u` — which should be enough to trace the failing request server-side. Claude Code's version of the same error surfaces no identifier at all, and Cowork's 502 gives only a Cloudflare `ray_id`. Same failure, three different levels of traceability.

5. **`retry_after` should be usable.** Every 502 advertises `"retryable": true, "retry_after": 60`, but a retry at +81 seconds returned another 502; recovery took roughly three minutes and two attempts.

### Error Messages/Logs

```shell
=== THE MOST TRACEABLE INSTANCE (claude.ai Chat) ===
One call out of 18 failed. Verbatim error, including the request_id:

{"error": "This connector's server hostname doesn't resolve or isn't reachable from this
network. The connector may be misconfigured.", "request_id": "req_011CezoxwxEMbE9gCwJv9e5u"}

Origin side for that same batch:
CallToolRequest received: 17 (Caddy: 17 x 200, 1 x 400 handshake probe)
CallToolRequest missing: 1 <- the 03_voice call above
service errors: 0
NRestarts: 0
The 17 that arrived include the calls immediately before and after the one that vanished,
so the origin was reachable and answering throughout.

=== SAME ERROR, CLAUDE CODE (no request_id surfaced) ===
This connector's server hostname doesn't resolve or isn't reachable from this network.
The connector may be misconfigured.

Origin side, 6 concurrent calls from Claude Code:
CallToolRequest received: 5 (all 200 OK)
CallToolRequest missing: 1
service errors: 0, NRestarts: 0

Caddy access log, same window (the 400s are normal handshake probes):
12:10:59 400 160.79.106.165
12:11:00 200 160.79.106.168
12:11:00 400 160.79.106.185
12:11:01 200 160.79.106.160
12:11:02 200 160.79.106.179
12:11:02 200 160.79.106.164
12:11:03 200 160.79.106.36

=== CLAUDE COWORK (cloud-hosted) ===
Error POSTing to endpoint: {"title":"Error 502: Bad gateway","status":502,
"error_name":"origin_bad_gateway","error_category":"origin","zone":"api.anthropic.com",
"cloudflare_error":true,"retryable":true,"retry_after":60}

Cloudflare ray IDs (all 2026-09-13, all on vault_edit):
03:17:43Z a3a4002208b827e1 502
backoff 70s
03:19:04Z a3a402185a21cd80 502 again (+81s, past the advertised retry_after of 60)
backoff 100s
200, write applied (~+187s after the first failure)
03:39:39Z a3a4203f2d7c22b9 502 -> backoff 95s -> 200
03:46:41Z a3a42a922a3e2322 502 -> backoff 95s -> 200
Every retry used a byte-identical payload, so payload size/shape is not the trigger.

=== EARLIER FAILURE WINDOW - CallTool counts per connector ===
Tool invocations not arriving while session setup for the same connectors did:
vault CallTool=5 last 01:58:43 <- 11:19 call never arrived
search CallTool=3 last 11:11:14 <- 11:19 call never arrived
evidence CallTool=0 none that day
legal CallTool=0 none that day
rkb CallTool=1 last 11:19:38 <- arrived, 200 OK
assets CallTool=1 last 11:19:46 <- arrived, 200 OK

During that window the origin logged a COMPLETE, successful session for one of the
"failing" connectors: "Created new transport" followed by ListToolsRequest -> 200 OK.
The connection was established and the tool list served; only the invocation was lost.

=== ORIGIN HEALTH ACROSS ALL OF THE ABOVE ===
NRestarts = 0 throughout (no crash, no automatic restart)
uptime ~19 days at the first failure; ~19 hours at the later ones, the only restart
in between being my own deliberate one for the stateless_http change
5xx responses in the entire access log: 0
401s present and correct (unauthenticated internet scanner probes)
```

### Steps to Reproduce

**No deterministic reproduction — it is a low-rate intermittent fault.** Reporting the measurement rather than a recipe, because my first attempt at a recipe did not survive testing.

1. Add a **custom remote MCP connector** (claude.ai → Settings → Connectors) pointing at a self-hosted Streamable HTTP MCP server you control — one whose access logs and application logs you can read.
2. Issue batches of tool calls to it and record the client-side success count.
3. **Compare that against the origin's access log and application log for the same window.**

Measured across six batches on three surfaces:

| batch | client | sent | arrived at origin | dropped |
|---|---|---|---|---|
| 1 | Claude Code | 6 (concurrent) | 5 | **1** |
| 2 | Cowork (cloud) | 6 | 6 | 0 |
| 3 | Claude Code | 8 (concurrent) | 8 | 0 |
| 4 | claude.ai Chat | 6 (sequential) | 6 | 0 |
| 5 | claude.ai Chat | 18 (sequential) | 17 | **1** |
| 6 | claude.ai Chat | 18 (sequential) | 18 | 0 |
| **total** | | **62** | **60** | **2** |

Roughly **3%**, on at least two different surfaces. Per-surface: Claude Code 1 drop in 14, claude.ai Chat 1 drop in 42 — numbers far too small to claim any surface is more affected than another.

**Concurrency is not the trigger.** I initially thought it was, because the first batch dropped one immediately. Batch 5 disproves it: 18 calls dispatched *sequentially*, one per turn-step, and one still vanished. Batch 6 was byte-for-byte the same request as batch 5 and came back clean, including the exact path that had failed. Larger batches simply give the fault more chances to fire.

> **Step 3 is the one that matters.** Comparing the client's success count against the origin's own logs is what distinguishes a delivery failure from an origin failure. Without it this presents as an origin or network fault — exactly what all three error messages assert, and where I wasted a day.

### Claude Model

Opus

### Is this a regression?

I don't know

### Last Working Version

_No response_

### Claude Code Version

Claude 1.52386.3 (41896e) 2026-09-11T17:35:10.000Z — Claude for Windows desktop app

### Platform

Anthropic API

### Operating System

Windows

### Terminal/Shell

Other

### Additional Information

### Versions and surfaces

- **Claude for Windows desktop app** — `Claude 1.52386.3 (41896e) 2026-09-11T17:35:10.000Z`
- **claude.ai Chat** — web, Opus 4.6
- **Claude Cowork, cloud-hosted** — not local. The currently-active status.claude.com incident *"Degraded functionality for Claude Cowork on Windows"* concerns **local** Cowork and a Sep 8 Windows update blocking local command execution, so it does not apply to these sessions.
- Windows 11
- The bundled Claude Code CLI version could not be read separately — the app ships as an MSIX package under `Program Files\WindowsApps`, which is ACL-protected, and `claude --version` is not on PATH for this install. The app version string above is what the app itself reports.
- status.claude.com reported **"Claude API: Operational"** throughout every failure described here.

### Possibly relevant: gateway egress rotates between requests

Within a single logical session, requests reach the origin from many distinct Anthropic egress addresses. Observed across one day: `160.79.106.36, .37, .160, .161, .163, .164, .165, .168, .173, .175, .176, .178, .179, .183, .184, .185, .187`. Consecutive requests in one round-trip routinely come from different nodes — e.g. a `400` from `.184` at 15:12:39 followed by the `200 OK` `CallToolRequest` from `.187` at 15:12:40.

Recording this as an observation only, not a claim about cause.

### Related issues

- **#48277**, **#48291** — same `Error POSTing to endpoint … 502` string, but `mcp-proxy.anthropic.com` and Anthropic-*hosted* connectors; #48291 closed as not planned
- **#69426** — a 502 on a connected MCP server driving a retry loop that drained a session's token budget
- **#6341** — closed as duplicate; different root cause (file token limits)
- **#64414** — different layer (custom *model API* gateway, not MCP), but a documented case of **Cowork and Code diverging against custom infrastructure**; closed as not planned
- **#61682** — Anthropic-*hosted* GitHub connector reporting "Connected" while exposing no tools; similar "connected but non-functional" presentation, but no custom origin and no delivery failure

This report differs from all of them in being a **custom self-hosted** connector, failing across **three surfaces** (local Claude Code, claude.ai Chat, and cloud Cowork), with **origin-side logs proving non-arrival**, a **measured drop rate over 44 calls**, a **`request_id` for one failing request**, and origin session state **experimentally eliminated**.

### Note

The origin hostname is deliberately omitted — it is a publicly-reachable endpoint fronting private material. Happy to share it privately with Anthropic if that helps trace `req_011CezoxwxEMbE9gCwJv9e5u` or the ray IDs above.

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

このリポジトリのコントリビューションガイドは索引されていません

評価

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

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

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