use tokio::io::{AsyncBufReadExt, AsyncReadExt, BufReader}; /// Reads an MCP (NDJSON or LSP Content-Length prefixed) message from a buffered async reader. /// Returns the raw JSON string payload if successful, or None on EOF or error. pub async fn read_mcp_message( stdin: &mut BufReader, ) -> Option { let mut length = 0; let mut line = String::new(); loop { line.clear(); if stdin.read_line(&mut line).await.unwrap_or(0) == 0 { return None; } if line.starts_with('{') { return Some(line.trim_end().to_string()); } let line = line.trim_end(); if line.is_empty() { break; } let lower_line = line.to_lowercase(); if let Some(len_str) = lower_line.strip_prefix("content-length:") { length = len_str.trim().parse().unwrap_or(0); } } if length == 0 { return None; } let mut buffer = vec![0; length]; if stdin.read_exact(&mut buffer).await.is_err() { return None; } String::from_utf8(buffer).ok() }