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('{') { let len = line.trim_end().len(); line.truncate(len); return Some(line); } let line = line.trim_end(); if line.is_empty() { break; } if line.len() >= 15 && line[..15].eq_ignore_ascii_case("content-length:") { length = line[15..].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() }