Summary
At line 62, the StreamWriter is created with AutoFlush = true, which flushes after each WriteLineAsync. However, there is no synchronization between the WriteLineAsync at line 105 (or 91, 113, 121) and the next ReadLineAsync at line 66. If the client sends a pipelined request (multiple requests before reading responses), and WriteLineAsync for the first response blocks or partially writes, the server may have already called ReadLineAsync for the second request, causing response ordering issues or losing requests. Additionally, if WriteLineAsync throws an exception DURING the write (not after), the StreamWriter may be left in a corrupt state with a partial line written.
Where
src/CodeIndex/Mcp/McpServer.cs:62 (AutoFlush = true, but no explicit synchronization)
src/CodeIndex/Mcp/McpServer.cs:66 (ReadLineAsync in loop, no backpressure check before reading next line)
src/CodeIndex/Mcp/McpServer.cs:91, 105, 113, 121 (WriteLineAsync calls with no await completion guarantee before loop continues)
Suggested approach
- After each WriteLineAsync, explicitly call
await writer.FlushAsync() to guarantee the line is fully written before proceeding
- Wrap WriteLineAsync + FlushAsync in a helper method to ensure this is always done together
- If WriteLineAsync or FlushAsync fails (e.g., IOException), mark the writer as broken and exit the loop rather than continuing to read requests
- Consider adding a timeout to FlushAsync to detect hung writes (e.g., client has closed stdout but not stdin)
- For pipelined requests, document that responses may be delayed if the write buffer fills (AutoFlush is not a guarantee of immediate availability)
- Add telemetry to count response write failures so operators can detect client communication breakdowns
Summary
At line 62, the StreamWriter is created with
AutoFlush = true, which flushes after each WriteLineAsync. However, there is no synchronization between the WriteLineAsync at line 105 (or 91, 113, 121) and the next ReadLineAsync at line 66. If the client sends a pipelined request (multiple requests before reading responses), and WriteLineAsync for the first response blocks or partially writes, the server may have already called ReadLineAsync for the second request, causing response ordering issues or losing requests. Additionally, if WriteLineAsync throws an exception DURING the write (not after), the StreamWriter may be left in a corrupt state with a partial line written.Where
src/CodeIndex/Mcp/McpServer.cs:62(AutoFlush = true, but no explicit synchronization)src/CodeIndex/Mcp/McpServer.cs:66(ReadLineAsync in loop, no backpressure check before reading next line)src/CodeIndex/Mcp/McpServer.cs:91, 105, 113, 121(WriteLineAsync calls with no await completion guarantee before loop continues)Suggested approach
await writer.FlushAsync()to guarantee the line is fully written before proceeding