Summary
When a JsonException is caught at line 108, the handler immediately attempts to write an error response at line 113: await writer.WriteLineAsync(errorResponse.ToJsonString(_jsonOptions)). If this WriteLineAsync throws (e.g., IOException from stdout closure), the exception is NOT caught by the inner try-catch at line 108; it propagates to the outer catch at line 115. However, inside that outer catch, the code assumes request is JsonObject, but request may still be null (from line 100 return) or may be a non-object type (if JsonNode.Parse returned one before throwing JsonException). This causes the error response at line 121 to be skipped, leaving the client with no response to the parse-error message and no indication that communication has failed.
Where
src/CodeIndex/Mcp/McpServer.cs:108-114 (JsonException handler writes error response without try-catch)
src/CodeIndex/Mcp/McpServer.cs:115-123 (outer exception handler assumes request is JsonObject, cannot respond if inner write failed)
src/CodeIndex/Mcp/McpServer.cs:66-70 (loop continues reading even after parse error write failure)
Suggested approach
- Wrap the error response write at line 113 in a nested try-catch that catches IOException and write-time exceptions separately
- If the error response write fails, log the original parse error AND the write failure to stderr, then continue the loop
- Do not attempt a second error response write (at line 121) if the first response write already failed
- Add a "response_sent" flag in the outer catch to track whether any response was successfully written
- For parse errors specifically, consider the error message already logged to stderr sufficient for diagnostics and continue without expecting client acknowledgment
- Test the scenario where client closes stdout before server writes the parse error response
Summary
When a JsonException is caught at line 108, the handler immediately attempts to write an error response at line 113:
await writer.WriteLineAsync(errorResponse.ToJsonString(_jsonOptions)). If this WriteLineAsync throws (e.g., IOException from stdout closure), the exception is NOT caught by the inner try-catch at line 108; it propagates to the outer catch at line 115. However, inside that outer catch, the code assumesrequest is JsonObject, butrequestmay still be null (from line 100 return) or may be a non-object type (if JsonNode.Parse returned one before throwing JsonException). This causes the error response at line 121 to be skipped, leaving the client with no response to the parse-error message and no indication that communication has failed.Where
src/CodeIndex/Mcp/McpServer.cs:108-114(JsonException handler writes error response without try-catch)src/CodeIndex/Mcp/McpServer.cs:115-123(outer exception handler assumes request is JsonObject, cannot respond if inner write failed)src/CodeIndex/Mcp/McpServer.cs:66-70(loop continues reading even after parse error write failure)Suggested approach