Hacktoberfest 2026: le issue che i maintainer hanno segnato per ottobre, aperte e adatte ai principianti. Sfoglia le issue Hacktoberfest

Modern subscriptions: a subscriptions/listen refused with HTTP 403 is retried eight times in silence

Aperta
#2,722 1 commento 0 reazioni 0 assegnatari Vedi su GitHub

I maintainer di solito rispondono entro 1 giorno

Nessuno ha ancora preso questa issue.

Valutazione

Difficoltà
4/5
Tempo stimato
3-5 giorni
Idoneità per principianti
30/100
Tipo di issue
Bug
Chiarezza
Abbastanza chiara
Stato di attività
Attiva
Stack tecnologico
typescript
Ambito
api

Direzione di ricerca

Start in core/mcp/inspectorClient.ts: the reconnect path runs from reconcileModernStreamStateAfterFailedRefresh (around lines 5762-5775) into scheduleModernReconnect (5806-5828) and onModernReconnectFailed (5835-5862), with the cap at MODERN_RECONNECT_MAX_ATTEMPTS (502-504). Compare with the never-acknowledged predicate in core/mcp/subscriptionAck.ts (49-52) and the tests in inspectorClient-subscriptions-era.test.ts. Done means a bare 403 on subscriptions/listen stops after one attempt with a visible refusal, while 5xx, 408, 429 and network errors still retry and 401 or insufficient_scope still goes through auth.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Descrizione

bug v2

Problem

On a modern-era server, when subscriptions/listen is refused with a bare HTTP 403 Forbidden (no WWW-Authenticate), the Inspector keeps re-sending the listen. It backs off exponentially up to its 8-attempt cap (roughly 60 s), then settles on a bare ended. The denial is never shown to the user.

That is the same silent eight-retry experience #2097 fixed for one failure shape, reached here through a different one.

This is a gap, not a regression.

  • #2097 / PR #2176 deliberately covered only one case: a listen the server closes gracefully before acknowledging it. Its predicate explicitly leaves "a transport failure, a timeout, or a pre-ack error response" retryable (core/mcp/subscriptionAck.ts:49-52).
  • That guarantee still holds: inspectorClient-subscriptions-era.test.ts passes 38/38 on the v2.11.0 tree.
  • The retry code is byte-identical between the #2176 merge (4d69dbf9) and v2/main.

It was found during the v2.11.0 milestone smoke (#2718) while driving #2515.

Observed

A logging proxy in front of a modern subscriptions test server answered every subscriptions/listen with a bare 403. Both versions sent the same 7 listens in about 6.6 s before the driver moved on:

Listen 2.11.0 2.10.1
1, on connect 0.00 s 0.00 s
2 +0.59 s +0.70 s
3 +1.05 s +1.16 s
4, user clicks Subscribe (attempt counter resets) (resets)
5 +0.56 s +0.68 s
6 +1.06 s +1.18 s
7 +2.07 s +2.16 s

The gaps are the reconnect backoff, min(500·2^n, 15000) ms. The only difference between versions is that 2.10.1 also ran OAuth discovery after every 403, which #2515 fixed in 2.11.0.

In the UI:

  • The Subscriptions section shows Subscriptions (0), because the URI was rolled back. The badge is gated on active, which the rollback clears, so the refusal appears nowhere.
  • The Protocol tab leaves each listen PENDING. That half is #2721.

Why it retries

  1. subscribeToResource → reconcileModernStreamStateAfterFailedRefresh (core/mcp/inspectorClient.ts:5762-5775) ends the stream only when modernNeverAcknowledged is set. Otherwise it calls scheduleModernReconnect() (:5806-5828).
  2. The filter stays non-empty after the rollback, because the resourcesListChanged opt-in remains (wantsModernStream, :5521). The later listens carry only that.
  3. onModernReconnectFailed (:5835-5862) counts up to MODERN_RECONNECT_MAX_ATTEMPTS = 8 (:502-504).
  4. The SDK (@modelcontextprotocol/client 2.3.1) does not retry the POST. It surfaces a bare 403 as SdkHttpError(ClientHttpNotImplemented, "Error POSTing to endpoint: Forbidden", {status: 403}). The error code is the same for every non-auth HTTP failure, so only data.status distinguishes them.

Expected

  • Don't retry a deterministic HTTP refusal. That covers a bare 403 (no WWW-Authenticate), 400, 404 and 405 from subscriptions/listen, classified by the HTTP status in the error data, not the SDK error code. A 401, or a 403 carrying insufficient_scope, keeps going through the auth flow.
  • Keep retrying transient failures: 5xx, 408 and 429 (consider honoring Retry-After), network errors and timeouts.
  • Say what happened. Give the refusal its own stream status, or reuse #2097's notice pattern, e.g. "The server refused subscriptions/listen (HTTP 403 Forbidden). Not retrying." Show it in the Subscriptions section even after the URI rollback.

Related: #2097 (the never-acknowledged case), #2721 (the Protocol tab leaves these requests PENDING), #2515 (a bare 403 no longer starts OAuth).

Lingua principale
TypeScript
Stelle
11.1k
Fork
1.5k
Merge medio
4h 14m
PR unite (30g)
162

Preparare l'ambiente

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Altre issue di modelcontextprotocol/inspector

Tutte le issue di modelcontextprotocol/inspector

Issue simili

Altre issue su TypeScript

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.