fix(stdio): iterate decoded message list in process_message dispatch#248
fix(stdio): iterate decoded message list in process_message dispatch#248TejGandham wants to merge 1 commit intocloudwalk:mainfrom
Conversation
Message.decode/1 always returns {:ok, messages} where messages is a
list, but the STDIO transport passed this list directly to
process_message/2 which expects a single map. This caused a BadMapError
on every incoming JSON-RPC message, making the STDIO transport
completely non-functional.
The client-side code (client/base.ex) and other transports (SSE,
StreamableHTTP) already handle the list correctly — STDIO was the
only outlier.
Fix: iterate with Enum.each/2 before dispatching each message.
There was a problem hiding this comment.
Summary
Solid fix. Message.decode/1 returns a list and passing it directly to process_message/2 (which expects a map) was a BadMapError on every message — exactly as described. The Enum.each/2 approach is correct and consistent with how the client side and SSE transport handle the same return shape.
One minor note: Enum.each/2 discards the return value of process_message/2, so any state updates that happen inside won't propagate. If process_message/2 ever needs to thread updated state through multiple messages in a batch, this will silently drop those updates. For a GenServer where state mutations go through handle_info/handle_call callbacks, this is likely fine as-is — but worth being aware of if process_message is ever extended to return {:noreply, new_state} style tuples.
Summary
Message.decode/1returns{:ok, messages}wheremessagesis always a list (seemessage.ex:376)stdio.ex:243passed this list directly toprocess_message/2, which expects a single mapBadMapErroron every incoming JSON-RPC message, making the STDIO server transport completely non-functionalFix
Iterate the decoded list with
Enum.each/2before dispatching each message individually — matching how the client-side code (client/base.ex:971) and other transports (SSE via pattern match{:ok, [message]}) already handle the list return.Before (broken)
After (fixed)
Verification
Tested against a real MCP client (roundtable) — the STDIO transport now correctly handles
initialize,tools/call, and other JSON-RPC messages. All existing tests continue to pass.🤖 Generated with Claude Code