Skip to content

StdioServerTransport fails to deserialize initial message when stdin starts with UTF-8 BOM #956

Description

@rnett

Description

When an MCP client writes a UTF-8 BOM (\uFEFF / bytes EF BB BF) at the beginning of stdin before the first JSON-RPC message, StdioServerTransport fails on deserialization and immediately closes the session.

We observed this behavior when running against OpenAI Codex CLI / Codex on Windows (codex-cli 0.147.0).

Stack trace

java.lang.IllegalArgumentException: Element class kotlinx.serialization.json.JsonLiteral is not a JsonObject
    at kotlinx.serialization.json.JsonElementKt.getJsonObject(JsonElement.kt:232)
    at io.modelcontextprotocol.kotlin.sdk.types.JSONRPCMessagePolymorphicSerializer.selectDeserializer(serializers.kt:493)
    at io.modelcontextprotocol.kotlin.sdk.shared.ReadBufferKt.deserializeMessage(ReadBuffer.kt:136)
    at io.modelcontextprotocol.kotlin.sdk.shared.ReadBuffer.readMessage(ReadBuffer.kt:54)
    at io.modelcontextprotocol.kotlin.sdk.server.StdioServerTransport.processorPump(StdioServerTransport.kt:209)

Root cause

StdioServerTransport reads bytes into ReadBuffer, splits on newlines, and passes the raw line string to deserializeMessage(line). When the first line contains a leading BOM, kotlinx.serialization parses \uFEFF{...} as a JsonLiteral rather than a JsonObject. JSONRPCMessagePolymorphicSerializer.selectDeserializer expects a JsonObject and throws IllegalArgumentException. Because this exception happens inside processorPump, the coroutine fails and drops the stdio connection.

Suggested fix

  1. In ReadBuffer (or deserializeMessage): trim leading BOM characters on incoming lines (line.trimStart('\uFEFF')).
  2. Alternatively, in StdioServerTransport: strip the leading EF BB BF bytes from the input Source before appending to the read buffer.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions