StdioTransport traps ("Negative value is not representable") when stdio is a socket, e.g. spawned by Node clients

Abierto Apto para principiantes
#327 0 comentarios 0 reacciones 0 asignados Ver en GitHub

Los mantenedores suelen responder en 2 días

Nadie ha tomado este issue todavía.

Evaluación

Dificultad
2/5
Tiempo estimado
1-3 horas
Aptitud para principiantes
73/100
Tipo de issue
Error
Claridad
Bien especificado
Estado de actividad
Activo
Stack tecnológico
swift

Línea de trabajo

Lee en Sources/MCP/Base/Transports/StdioTransport.swift el código alrededor de las líneas indicadas en setNonBlocking(fileDescriptor:) y restoreFlags. El issue incluye la conversión propuesta y un escenario reproducible de Node con socketpair; añade una prueba de regresión con socketpair para verificar que el transporte se conecta sin provocar un trap y ejecuta las pruebas de Swift pertinentes. Se considerará terminado cuando stdin/stdout respaldados por sockets ya no provoquen el trap por valor negativo.

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

Descripción

Summary

Since #297 (merged 2026-10-31, on main, not in 0.12.1), StdioTransport.connect() traps when stdin/stdout is a socket:

Fatal error: Negative value is not representable

Node's child_process.spawn with stdio: 'pipe' uses socketpairs on macOS, and fstat on a socket reports st_dev == -1. dev_t is signed (Int32 on Darwin), so UInt64(status.st_dev) traps. Every Node-based MCP client hits this: Claude Desktop and Claude Code both report "Connection closed" right after initialize.

Affected lines: StdioTransport.swift L147, L159–160. Symbolicated crash: StdioTransport.setNonBlocking(fileDescriptor:) (StdioTransport.swift:147) ← StdioTransport.connect() ← Server.start(transport:).

Repro (macOS)

Build any server using StdioTransport(), then:

// node repro.js /path/to/server
const p = require("child_process").spawn(process.argv[2], [], { stdio: ["pipe", "pipe", "inherit"] });
p.on("exit", (c, s) => console.log("exit", c, s)); // → exit null SIGTRAP
p.stdin.write(JSON.stringify({ jsonrpc: "2.0", id: 0, method: "initialize",
  params: { protocolVersion: "2025-06-18", capabilities: {}, clientInfo: { name: "n", version: "1" } } }) + "\n");

Shell pipes don't reproduce it (st_dev == 0), which is why terminal testing passes:

$ python3 -c "import os,socket; a,_=socket.socketpair(); r,_=os.pipe(); print(os.fstat(a.fileno()).st_dev, os.fstat(r).st_dev)"
-1 0
Fix

Convert by bit pattern instead of value (the values are only compared for identity):

-flags: flags, device: UInt64(status.st_dev), inode: UInt64(status.st_ino))
+flags: flags, device: UInt64(truncatingIfNeeded: status.st_dev), inode: UInt64(truncatingIfNeeded: status.st_ino))

(and the same in restoreFlags). Patch with this change: https://github.com/noisyneighborstudio/swift-sdk/commit/b7a26b8d887fda9389a81f0c5feaa34e3d7e8ff7. Happy to open a PR with it plus a socketpair regression test.

Lenguaje dominante
Swift
Estrellas
1.6k
Forks
270
Merge medio
2 d 7 h
PR fusionados (30 d)
15

Preparar el entorno

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.