`Client.connect` busy-loops at 100% CPU when the transport reaches EOF before `initialize` completes
Los mantenedores suelen responder en 7 días
Nadie ha tomado este issue todavía.
Evaluación
- Dificultad
- 3/5
- Tiempo estimado
- 1-2 días
- Aptitud para principiantes
- 72/100
- Tipo de issue
- Error
- Claridad
- Bastante claro
- Estado de actividad
- Tranquilo
- Stack tecnológico
- swift
- Área
- backend, networking
Línea de trabajo
Start in Sources/MCP/Client/Client.swift at the message-handling task created by Client.connect and inspect how connection.receive() behaves when its AsyncThrowingStream finishes. Run the described /usr/bin/true StdioTransport reproduction first. Done means EOF stops further receive polling and connect/_initialize throws a connection-closed error instead of hanging.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
If a spawned MCP server dies (or closes its stdout) during startup — before the client's initialize handshake finishes — Client.connect(transport:) never returns and one core sits pinned at 100%.
What I see: a stdio server that exits immediately on launch. ps shows the host process in state R, and sample <pid> shows the spin inside closure #1 in Client.connect → AsyncThrowingStream.Iterator.next().
The message-handling loop in Sources/MCP/Client/Client.swift is (trimmed):
task = Task {
guard let connection = self.connection else { return }
repeat {
if Task.isCancelled { break }
do {
let stream = await connection.receive()
for try await data in stream {
if Task.isCancelled { break }
// decode + dispatch
}
} catch { break }
} while true
}
// ...
return try await _initialize()
When the transport hits EOF, the stream from receive() finishes, the for try await completes without throwing, and while true immediately loops back and calls receive() again, which returns another already-finished stream. Nothing sleeps or exits on end-of-stream, so it spins. Meanwhile connect has moved on to await _initialize(), whose response never arrives because the server is gone, so connect is parked forever on a continuation nothing resumes.
Minimal repro: spawn /usr/bin/true via Process with two Pipes, wrap the pipe fds in a StdioTransport(input:output:), build a Client, and try await client.connect(transport:). Just re-ran this against v0.12.1: connect has neither returned nor thrown 8 seconds in, and ps samples the process at ~100% CPU for the whole wait (96.6 / 100.0 / 100.0 / 100.0 over four 1.5s samples).
Two changes would fix it:
- The loop should stop (or back off) when the underlying stream finishes rather than re-polling a finished stream — a finished transport stream means the connection is gone.
connect/_initializeshould then fail with a connection-closed error instead of hanging.
For what it's worth, my workaround is to race connect against a timeout and call client.disconnect() on expiry — disconnect() cancels that task and resumes the pending initialize with an error, so connect throws instead of hanging. Separately I had to set signal(SIGPIPE, SIG_IGN), because writing to the dead server's stdin was raising SIGPIPE and taking down the whole host process. I'd be happy to turn the loop-termination part into a PR if that's welcome.
- Lenguaje dominante
- Swift
- Estrellas
- 1.5k
- Forks
- 252
- Métricas de merge de PR
- Sin PR fusionados en 30 d
Preparar el entorno
- 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/swift-sdk
-
NetworkTransport leaks the underlying socket (CLOSE_WAIT) when reconnection is disabled and the receive loop terminatesPosiblemente ocupada @skirrellyjones la tomó hace 37 días. Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 88/100
modelcontextprotocol/swift-sdk#282 ·
Los mantenedores suelen responder en 7 días
-
Value decoding changes data-URL-looking JSON strings into Value.dataPosiblemente ocupada @bitbemol la tomó hace 48 días. Abiertobug
Dificultad 2/5 1-3 horas Aptitud para principiantes 76/100
modelcontextprotocol/swift-sdk#277 ·
Los mantenedores suelen responder en 7 días
-
enhancement
Dificultad 1/5 Menos de una hora Aptitud para principiantes 78/100
modelcontextprotocol/swift-sdk#274 ·
Los mantenedores suelen responder en 7 días
-
`HTTPClientTransport` fails to build on Windows: `#if !os(Linux)` guards no longer match the `EventSource` platform conditionQuizá libre de nuevo Un pull request para esta issue se cerró sin fusionarse. Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 85/100
modelcontextprotocol/swift-sdk#261 ·
Los mantenedores suelen responder en 7 días
-
Value: add numberValue (Double?) that coerces .int and .doublePosiblemente ocupada @gsdali la tomó hace 159 días. Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 76/100
modelcontextprotocol/swift-sdk#225 ·
Los mantenedores suelen responder en 7 días
Todos los issues de modelcontextprotocol/swift-sdk
Issues similares
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 75/100
Los mantenedores suelen responder en 1 día
-
[BUG] File transcription skips audio chunks shorter than one secondPosiblemente ocupada @sabbah13 la tomó hoy. Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 72/100
altic-dev/FluidVoice#1161 ·
Los mantenedores suelen responder en 1 día
-
swift.md: `Date(myString, strategy: .iso8601)` example omits `try` — the initializer is throwingAbierto
Dificultad 1/5 Menos de una hora Aptitud para principiantes 88/100
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 62/100
githubnext/desktop-tools#25 ·
Los mantenedores suelen responder en 1 día
-
bug core p3
Dificultad 2/5 1-3 horas Aptitud para principiantes 70/100
RunanywhereAI/runanywhere-sdks#1083 ·
Los mantenedores suelen responder en 5 días