◉CLAUDE LABJP
●2.1.301 — Adds the vim % motion, LaTeX math rendering in the VS Code panel, and a retry-watchdog limit for usage-limit waits (10/15)●2.1.299 — Conversations over 200K tokens left idle about 54 minutes get compacted; MCP allow rules now match only the server they name●SONNET 4.5 — Retires on the Claude API on 11/30, 45 days left. Migrate to Sonnet 5.5●WINDOWS — Reports say hooks break silently only on Japanese-locale Windows; check the character encoding first●FAST MODE — Opus 5.5 fast mode is out of research preview and no longer needs the beta header (10/15)●NEW — I Put a Ten-Line Promise File at the To…●2.1.301 — Adds the vim % motion, LaTeX math rendering in the VS Code panel, and a retry-watchdog limit for usage-limit waits (10/15)●2.1.299 — Conversations over 200K tokens left idle about 54 minutes get compacted; MCP allow rules now match only the server they name●SONNET 4.5 — Retires on the Claude API on 11/30, 45 days left. Migrate to Sonnet 5.5●WINDOWS — Reports say hooks break silently only on Japanese-locale Windows; check the character encoding first●FAST MODE — Opus 5.5 fast mode is out of research preview and no longer needs the beta header (10/15)●NEW — I Put a Ten-Line Promise File at the To…
Articles/Claude Code
⟐ Claude Code/2026-06-25Advanced

The Day a Non-Responding MCP Call Swallowed an Entire Unattended Run — Owning the Stop With Your Own Deadline

When a remote MCP tool call stops responding, an unattended scheduled run just keeps waiting. Instead of leaving the cutoff entirely to the platform, here is how I designed my own deadline and a per-connector circuit breaker to own the stop — with working code.

claude-code132mcp20agent14timeout10reliability18

✦ Premium Article

In a scheduled run's log, a step that normally finishes in tens of seconds shows only "started," and then nothing after it. Re-run it and it passes fine. At first I let it go as a transient hiccup, but once it started landing on the same spot once or twice a week, I couldn't ignore it. The cause was a tool call sent to a remote MCP server that never returned a response — and our side kept waiting for it.

If you're working interactively, you step in the moment something feels stuck. But an unattended scheduled run has no one to step in. It burns the run's time budget still waiting for a response, and finishes without ever reaching the later steps. The worst part was that it wasn't even recorded as a failure.

The June 25 update fixed the behavior where a remote MCP tool call would wait indefinitely with no response; it now interrupts with an error after a set time instead of waiting forever. That's a real step forward. But what this fix gives you is a guarantee that "a failure will eventually come back" — not a decision about what your unattended run does with that failure. Today is my record of redesigning exactly that part, anchored to how I actually run things as an indie developer.

"Hanging" and "a failure returns" are two completely different operational modes

A state that hangs with no response and a state that returns an explicit error differ in operational character far more than the code suggests.

A hang robs you of the chance to actively decide anything. No exception and no return value arrive, so neither your try/except nor any downstream branch fires. The process just waits, and until the run's outer timeout arrives and kills it from the outside, the log holds only "started." Looking back afterward, there's barely a trace of where, or for how many minutes, it was waiting.

When a failure returns, on the other hand, you can decide. Retry, give up on this connector for now, or push the later steps forward anyway. Now that the platform interrupts a non-response, you finally stand at the entrance to that decision.

That said, the grace period before the platform cuts off can be long for an unattended run. When the overall run budget is short, cutting yourself off inside the outer limit leaves more time for later steps. Rather than delegating the cutoff wholesale to the platform, laying your own deadline further inside is the starting point.

Decide up front which layer stops the call

The most accident-prone part of timeout design is having several layers each hold a different limit, leaving it ambiguous who stops first. To keep this straight, narrow the layer that owns the stop down to one.

In my setup, I line them up from the inside out. First, each individual MCP tool call gets a call deadline, kept clearly shorter than the overall run budget. Next comes a step deadline for a step that bundles several calls. Finally there's a run deadline watching the whole scheduled run, and I make that one match the platform's limit.

The crucial part is keeping inner limits strictly shorter than outer ones. If the call deadline is longer than the step deadline, your own cutoff never fires and you end up swallowed by the outermost layer after all. When unsure of the numbers, work backward from what fraction of the outer budget you can spend on a single call. To leave time for the remaining steps, holding one call to at most roughly a third of the total budget felt realistic in my experience.

✦

Thank you for reading this far.

Continue Reading

What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.

WHAT YOU'LL LEARN
✦Separate what actually breaks when a remote MCP call hangs in an unattended run, so you can decide which layer should own the cutoff
✦Implement an asyncio wrapper that puts your own deadline inside the platform default and distinguishes a hang, a real error, and a normal response before retrying
✦Automate skip decisions with a per-connector circuit breaker so one broken connector can't drag the rest of the run's time down with it
Secure payment via Stripe · Cancel anytime
✦

Unlock This Article

Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.

or
Unlock all articles with Membership →
Share

Thank You for Reading

Claude Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • ✦Copy-paste ready implementation code
  • ✦New advanced guides published daily
  • ✦$5/mo or $10 for lifetime access
View Membership →

Related Articles

⟐ Claude Code2026-03-24
How to Automate Game Development with Claude Code × unity-mcp — A Complete Workflow from Concept to Release
Learn how to combine Claude Code with unity-mcp to automate Unity game development. The hcg-workflows skill set provides an 8-phase workflow from planning to deployment.
⟐ Claude Code2026-08-28
A small script that catches invisible characters in plugin names before you install
Control characters and zero-width characters hiding in plugin or skill names are invisible in a terminal listing. I built six deliberately confusing names, compared what ls actually shows, and wrote a short check you can run before installing anything — plus an honest note on what that check misses.
⟐ Claude Code2026-08-26
I decide the prompt cache TTL by where I come back to, not how long I was away
Claude Code v2.1.242 added promptCacheTtl and subagentPromptCacheTtl. Whether the one-hour cache pays off depends on returning to the same directory and the same git state, not on how long the break was. Here is the order I check things in.