Skip to content

429 in streamable-http-transport.ts doesn't inspect Retry-After — incorrect retry behavior #96

Description

@SirBrenton

Summary

Finding

Ran pitstop-check against the MCP transport layer:

src/transports/streamable-http-transport.ts:153 — 429 handled without Retry-After

Why it matters

In MCP transport, a 429 can mean different things:

  • Transient pressure → wait and retry
  • Quota exhaustion → do not retry

When Retry-After is ignored, the transport retries quota exhaustion cases that can't recover until the window resets.

Example

curl -s -X POST https://web-production-273d3.up.railway.app/classify \
  -H "Content-Type: application/json" \
  -d '{"status":429,"headers":{"retry-after":"600"}}'

Returns STOP — do not retry.

Static check: github.com/SirBrenton/pitstop-check

Reproduction steps

  1. Clone the repo and run pitstop-check against the transport layer:
npx pitstop-check src/transports/streamable-http-transport.ts
  1. Observe warning at line 153:
    429 handled without Retry-After — likely incorrect retry behavior

Expected behavior:
429 responses with a Retry-After header should use that value to determine wait time before retry. Quota exhaustion cases (long Retry-After) should not retry at all.

Actual behavior:
All 429s handled uniformly without inspecting Retry-After.

No distinction between transient pressure and quota exhaustion.

Environment

Static analysis only — no runtime reproduction required.

  • OS: macOS
  • Node: current LTS
  • Transport: streamable-http-transport.ts
  • Finding confirmed in current main branch (cloned 2026-04-02)
  • Client: n/a (static code analysis)

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions