CLAUDE LABJP
MEMORY — Claude Code closes a cluster of long-session memory leaks, including MCP stdio stderr piling up to 64 MB per server and LSP documents staying open indefinitelyTABLES — Very large markdown tables no longer stall rendering; tables over 200 rows now show the first 200 with a "… N more rows" noticeSPEED — Sessions carrying many deny/ask permission rules no longer lose seconds every turn: rule matchers are compiled once and cachedTOOLS — print/SDK sessions with many MCP tools get up to 7x faster tool rounds thanks to cached tool-pool assemblyARTIFACTS — Claude Code Artifacts turn session work into live, shareable web pages that update in place — useful for PR walkthroughs and dashboardsDEADLINE — Opus 4.7 fast mode is removed on July 24; speed: "fast" will error, so move to Opus 4.8 fast mode before thenMEMORY — Claude Code closes a cluster of long-session memory leaks, including MCP stdio stderr piling up to 64 MB per server and LSP documents staying open indefinitelyTABLES — Very large markdown tables no longer stall rendering; tables over 200 rows now show the first 200 with a "… N more rows" noticeSPEED — Sessions carrying many deny/ask permission rules no longer lose seconds every turn: rule matchers are compiled once and cachedTOOLS — print/SDK sessions with many MCP tools get up to 7x faster tool rounds thanks to cached tool-pool assemblyARTIFACTS — Claude Code Artifacts turn session work into live, shareable web pages that update in place — useful for PR walkthroughs and dashboardsDEADLINE — Opus 4.7 fast mode is removed on July 24; speed: "fast" will error, so move to Opus 4.8 fast mode before then
Articles/API & SDK
API & SDK/2026-06-28Advanced

Did That Post Actually Go Through? Safely Retrying an Interrupted MCP Write Without Double-Executing

When an MCP write tool call is interrupted by a dropped connection, you can't tell whether the server ran it. Here's why naive retries cause double-execution, and a working wrapper that uses idempotency keys and a reconcile read to retry safely — with examples from an unattended pipeline.

Claude API115MCP44idempotency6automation93reliability17

Premium Article

One of my unattended publishing jobs once got its connection cut mid-request while posting to X. All I got back was a timeout error, with no way to know whether the post had landed. The log recorded a "failure" — yet a few minutes later the same post was sitting on the timeline. The server had succeeded; only the result never reached me.

If I had naively decided "it failed, so retry," two identical posts would have ended up side by side. As an indie developer automating announcements across several sites, that is an incident that has nothing to do with content quality. To a reader, posting the same thing twice just signals sloppy operations. If you are going to run write-type tool calls unattended, you have to design for this "did it go through?" state head-on.

"Failed" and "uncertain" are not the same thing

There are two kinds of errors. One is a clear rejection — the server says "I will not accept your request." The other is unknown — the connection dropped before any response came back. The first is safe to retry, because you know the server did nothing.

The troublesome one is the second. The request may have reached the server and been processed, or it may have been cut off before arrival. From your side, you cannot tell. This is the well-known problem in distributed systems: the sender can never be certain the receiver executed. Timeouts, connection resets, and mid-stream disconnects all belong in this "uncertain" bucket.

The June 27, 2026 update improved MCP resilience in Claude Code so that partial responses are preserved even when a stream is cut mid-flight. The receiving side is genuinely more robust now. Even so, the uncertainty that remains the moment a write tool call is interrupted — "did the server execute it?" — is not something a more resilient receiver alone can remove. That part lives in your application.

A common implementation trap is error classification. An HTTP 5xx can mean "the server failed to process" or "it processed but only the response was lost," so pushing it straight to failed is dangerous. I treat every ambiguous error as uncertain. Since uncertain operations are settled by reconciliation during recovery, over-classifying as uncertain never causes double-execution — whereas mislabeling a truly uncertain call as failed leads to it immediately. When in doubt, fall to the safe side: uncertain.

Why naive retries cause double-execution

When people write retry logic, they usually think in two states: success or failure, and retry on failure. That design is the breeding ground for double-execution.

If you collapse "uncertain" into "failed," you re-run even the cases that actually succeeded on the server. A post becomes a double post, a charge becomes a double charge, an email becomes a second copy. That is exactly the trap I fell into first: I wrapped my retry logic in a sloppy except Exception: and unconditionally resent inside it. It never reproduced in testing, and the first double post showed up on a night when the production connection got flaky.

The correct approach splits state into three: committed, failed, and uncertain. Only failed is safe to retry directly. For uncertain, you always insert one extra step — "check before you redo."

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
A three-state ledger that treats a dropped connection as 'uncertain' rather than 'failed', and why two states break down
A Python wrapper that protects MCP tools without idempotency support, using a correlation token and a reconcile read
A table for deciding when retrying is safe and when it isn't, weighed by the cost of a duplicate vs the cost of a miss
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

API & SDK2026-07-08
Contract-Test Every Tool Before You Submit or Automate an MCP Connector
A connector that works once in a chat can still break silently in an unattended job through misread response shapes or double-fired writes. Here is a small harness that machine-checks tool descriptions, response contracts, idempotency, and latency, with measured numbers.
API & SDK2026-07-05
Fable 5 Is Back Worldwide and Sonnet 5 Is the Default — Where Each of the Three Models Belongs in a Solo Automation Stack
With Fable 5 redeployed worldwide and Sonnet 5 now the default, solo automation suddenly has three capable top-tier models to reach for. Instead of ranking them, this piece assigns each a role and captures that in a policy object with a fallback ladder and run-level logging.
API & SDK2026-07-02
Introductory Pricing Has an End Date — Effective-Dated Cost Forecasts for the Sonnet 5 Price Step
Claude Sonnet 5's introductory $2/$10 pricing ends on 2026-08-31 and reverts to $3/$15. A static price map will quietly understate your September forecast by a third. Here is an effective-dated price table and forecast design that absorbs the step.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links
See all →