anthropics / anthropics/claude-code

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

Offen
#93,956 0 Kommentare 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen
area:cowork area:mcp bug
Vorherrschende Sprache
Python
Sterne
145k
Forks
23.1k
PR-Merge-Kennzahlen
PR-Kennzahlen ausstehend

Beschreibung

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

Beitragsleitfaden

Für dieses Repository ist kein Beitragsleitfaden indexiert

Bewertung

Dieses Issue wurde noch nicht bewertet.

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.