anthropics / anthropics/claude-code
[BUG] Custom MCP connector: tool calls dropped before reaching origin — Claude Code, claude.ai Chat and Cowork
- 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.