Streamable HTTP client: update the stored endpoint URI after a 308
Los mantenedores suelen responder en 2 días
@connor4312 ya está trabajando en esto.
Desde el 16/10/2026.
Evaluación
Este issue todavía no se ha evaluado.
Descripción
Follow-up from #1203 and #1367.
Problem
After #1367, the default Streamable HTTP client follows same-origin 307 and 308 redirects. But it never saves the new location. Every request still goes to the configured URI first and gets redirected again.
A 308 means the move is permanent, so the client could send later requests straight to the new URI.
Current behavior
At a156be8, the URI lives in StreamableHttpClientTransportConfig::uri. The worker clones the config once and never changes it. Each request copies the URI from there:
- POST:
post_request, and the initialize POSTs at startup and in the fallback path. - Standalone GET stream: resumption with
Last-Event-IDuses its own copy inStreamableHttpClientReconnect. - SSE on a POST response: resumption gets a copy too.
- Re-initialization after a 404:
perform_reinitialization. - DELETE on close:
SessionCleanupInfoholds its own copy, used at exit.
All of these requests use the same reqwest::Client, so the redirect policy applies to GET and DELETE too, not only POST.
reqwest gives us the final URL through Response::url(), but not the status of each hop. The Policy::custom closure sees each hop's status. However, one policy is shared by every request on the client, and it can't tell which request a hop belongs to.
Proposal
- Only save the new URI when every hop in the chain is a 308. If any hop is a 307, keep the configured URI.
- Have the
runloop keep the current URI, since it already owns the session state. Use that URI for new POSTs, new GET streams, re-initialization and the DELETE. - Return the final URL from the client to the worker.
StreamableHttpPostResponsedoesn't carry a URL today.
To find out whether every hop was a 308, we could:
- Stop on 308 in the policy and follow it by hand in the reqwest
StreamableHttpClientimpl, with the same origin and hop-limit checks. - Record hops from the policy closure into shared state. This is unreliable when concurrent requests start from the same URI.
Open questions
- Same-origin is already enforced, so only the path and query can change. Do we need any other check?
- Should the session ID carry over to the new URI, or should the client re-initialize?
- OAuth:
AuthorizationManagerkeeps its ownbase_url. It's the fallbackresource, and the protected resource metadataresourceis checked against it. If the transport URI moves andbase_urldoesn't, they no longer match, and there's no way to updatebase_urltoday. Should we skip the update whenAuthClientwraps the transport, or move both? - Requests and streams already in flight keep the old URI. Is that fine, or should resumption pick up the new one?
- Default client only, or also clients passed to
with_client?
Related
- #1203: the original redirect report
- #1367: follows same-origin 307/308 in the default client
- The TypeScript and Python SDKs don't update the stored URL either. Both follow same-origin redirects and keep the configured URL (TypeScript, Python).
- Lenguaje dominante
- Rust
- Estrellas
- 4k
- Forks
- 662
- Merge medio
- 3 d 11 h
- PR fusionados (30 d)
- 36
Preparar el entorno
Inicia el contenedor de desarrollo del proyecto en tu navegador, con tu propia cuenta de GitHub.
- Sin Dockerfile ni archivo de Docker Compose
- Sin plantilla de pull request
- Leer la guía de contribución
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de modelcontextprotocol/rust-sdk
-
Streamable HTTP client: a 401 or 403 with a JSON-RPC error body and no WWW-Authenticate loses its HTTP statusPosiblemente ocupada @aton-of-data la tomó hace 7 días. Abiertobug P2 ready for work T-security T-transport
Dificultad 2/5 1-3 horas Aptitud para principiantes 68/100
modelcontextprotocol/rust-sdk#1339 ·
Los mantenedores suelen responder en 2 días
-
auth: refresh_token() requests offline_access that was never granted, so refreshes fail with invalid_scopePosiblemente ocupada @jstar0 la tomó hace 10 días. Abiertobug P1 ready for work T-security T-transport
Dificultad 2/5 1-3 horas Aptitud para principiantes 65/100
modelcontextprotocol/rust-sdk#1330 ·
Los mantenedores suelen responder en 2 días
-
P3 question Stale T-documentation T-enhancement
Dificultad 1/5 Menos de una hora Aptitud para principiantes 86/100
modelcontextprotocol/rust-sdk#1155 · 1 comentario ·
Los mantenedores suelen responder en 2 días
-
outputSchema is generated for the deserialize contract; tool results are serialisedPosiblemente ocupada @connor4312 la tomó hace 2 días. Abiertobug P2 ready for work T-handler
modelcontextprotocol/rust-sdk#1374 · 2 comentarios · 1 asignado ·
Los mantenedores suelen responder en 2 días
-
Expose OAuth discovery and registration results for application-owned flowsPosiblemente ocupada @connor4312 la tomó hace 2 días. Abiertoenhancement P2 ready for work T-security
modelcontextprotocol/rust-sdk#1371 · 1 comentario · 1 asignado ·
Los mantenedores suelen responder en 2 días
Todos los issues de modelcontextprotocol/rust-sdk
Issues similares
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
yologdev/yoyo-evolve#1053 ·
-
bug lompi security sev-9
Dificultad 2/5 1-3 horas Aptitud para principiantes 68/100
-
area:config area:security bug good first issue platform:linux platform:windows priority:medium
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
rtk-ai/rtk#4651 · 1 comentario ·
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 67/100
niravpatidar37/mcpsum#80 ·
Los mantenedores suelen responder en 1 día