Skip to content

StdioServerTransport: onClose callback not called when stdin receives EOF #708

@aequicor

Description

@aequicor

Description

When running an MCP server with StdioServerTransport inside a Docker container,
the server.onClose and session.onClose callbacks are never triggered when the
MCP client (opencode) closes the connection by closing stdin.

Steps to Reproduce

  1. Start an MCP server using StdioServerTransport
  2. Connect a client via stdio (e.g. opencode)
  3. Close the client

Expected Behavior

server.onClose or session.onClose callback is called, allowing the server
process to exit gracefully.

Actual Behavior

Neither server.onClose nor session.onClose is triggered. The log shows
session removal:
[DefaultDispatcher-worker-3] INFO ServerSessionRegistry - Removing session: 3a737289-2a49-454d-9cb1-a692c646634b

But the process continues to hang indefinitely.

Workaround

Wrapping System.in to detect EOF manually:

class EofDetectingInputStream(
    private val delegate: InputStream,
    private val onEof: () -> Unit,
) : InputStream() {
    override fun read(): Int {
        val b = delegate.read()
        if (b == -1) onEof()
        return b
    }

    override fun read(b: ByteArray, off: Int, len: Int): Int {
        val n = delegate.read(b, off, len)
        if (n == -1) onEof()
        return n
    }
}

val transport = StdioServerTransport(
    inputStream = EofDetectingInputStream(System.`in`) { exitProcess(0) }.asSource().buffered(),
    outputStream = System.out.asSink().buffered(),
)

Environment

  • kotlin-sdk version: (укажи свою)
  • Kotlin version: (укажи свою)
  • OS: Linux (Docker container)
  • JVM: Eclipse Temurin 17

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions