Hacktoberfest 2026: los issues que los mantenedores marcaron para octubre, abiertos y aptos para principiantes. Explorar issues de Hacktoberfest

StdioTransport.send() still interleaves concurrent sends under EAGAIN backpressure — #252 was closed without a merged fix

Abierto
#263 0 comentarios 0 reacciones 0 asignados Ver en GitHub

Nadie ha tomado este issue todavía.

Evaluación

Dificultad
4/5
Tiempo estimado
3-5 días
Aptitud para principiantes
58/100
Tipo de issue
Error
Claridad
Bastante claro
Estado de actividad
Tranquilo
Stack tecnológico
swift
Área
networking

Línea de trabajo

Start at StdioTransport.send() and inspect the write loop around the EAGAIN backpressure sleep and actor suspension. Reproduce with a slowly drained pipe, a large send, and a concurrent small send; done means concurrent newline-delimited JSON frames remain intact while backpressure is retried.

Escrito por el modelo de indexación a partir del texto del issue.

Descripción

bug

Summary

StdioTransport.send() can splice the bytes of one JSON-RPC frame into the
middle of another when two sends run concurrently and the first hits stdout
backpressure. This corrupts the newline-delimited framing for any client
reading the stream.

This is the same defect reported in #252 (2026-07-02). That issue was closed
by its reporter the next day with no linked commit or PR, and the code on
main today is unchanged — the bug is still present. Filing fresh with an
independent, in-the-wild reproduction.

Root cause

StdioTransport is an actor, but send(_:) contains an await inside its
write loop — the EAGAIN backpressure sleep:

} catch let error where MCPError.isResourceTemporarilyUnavailable(error) {
    try await Task.sleep(for: .milliseconds(10))   // ← actor reentrancy point
    continue
}

Actor isolation guarantees mutual exclusion only between suspension
points. While one send is suspended in that sleep mid-frame, a second
send enters the actor and writes its complete frame into the middle of the
first one.

Observed in the wild

Version 0.12.1, macOS 15 (Darwin 25.5), a stdio MCP server whose
initialize result carries a ~1.9 KB instructions string. A pipelining
client sent initialize + a tools/call back-to-back; the captured stdout
shows the tool response spliced mid-word into the initialize result:

...has not made any bucket visi{"id":2,"jsonrpc":"2.0","result":{...}}
ble to agents yet...

Both frames are unparseable to a line-delimited JSON reader at that point.
Any client that issues parallel tool calls (several do) can trigger this
whenever a response exceeds what the pipe accepts in one write — no
misbehaving client required.

Reproduction sketch

Same shape as #252's: create the transport over a pipe the reader drains
slowly, start a send large enough to hit EAGAIN (hundreds of KB, or a small
pipe), and issue a second small send while the first is suspended. The small
frame lands inside the large one.

Suggested fix

Serialize sends so one completes before the next begins — either drop to a
blocking write for the remainder of a frame, or chain sends FIFO. We shipped
the FIFO as a wrapper in our server and it eliminates the corruption:

private var lastSend: Task<Void, Never>?

func send(_ data: Data) async throws {
    let previous = lastSend
    let task = Task<Void, Error> { [base] in
        await previous?.value
        try await base.send(data)
    }
    lastSend = Task { try? await task.value }
    try await task.value
}

The same pattern inlined into StdioTransport.send (chain before the write
loop) would fix it at the source. Happy to turn this into a PR if that's
welcome.

Lenguaje dominante
Swift
Estrellas
1.5k
Forks
243
Métricas de merge de PR
Sin PR fusionados en 30 d

Guía de contribución

Abrir la guía de contribución

Primeros pasos

  1. Lee el issue completo y luego la guía de contribución del proyecto.
  2. Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
  3. Haz un fork del repositorio y trabaja en una rama.
  4. Abre un pull request que haga referencia al número del issue.

Más de modelcontextprotocol/swift-sdk

Todos los issues de modelcontextprotocol/swift-sdk

Issues similares

Más issues de Swift

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.