use crate::error::{Error, Result};
use crate::mcp::protocol::{JsonRpcRequest, JsonRpcResponse};
use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader};
use tracing::{debug, error, trace};
pub struct StdioTransport {
stdin: BufReader<tokio::io::Stdin>,
stdout: tokio::io::Stdout,
}
impl StdioTransport {
pub fn new() -> Self {
Self {
stdin: BufReader::new(tokio::io::stdin()),
stdout: tokio::io::stdout(),
}
}
pub async fn read_request(&mut self) -> Result<Option<JsonRpcRequest>> {
loop {
let mut line = String::new();
match self.stdin.read_line(&mut line).await {
Ok(0) => {
debug!("EOF reached on stdin");
return Ok(None);
}
Ok(_) => {}
Err(e) => {
error!("Failed to read from stdin: {}", e);
return Err(Error::Io(e));
}
}
if line.ends_with('\n') {
line.pop();
if line.ends_with('\r') {
line.pop();
}
}
if line.trim().is_empty() {
trace!("Received empty line, skipping");
continue;
}
trace!("Received line: {}", line);
match serde_json::from_str::<JsonRpcRequest>(&line) {
Ok(request) => {
debug!(
"Parsed request: method={}, id={:?}",
request.method, request.id
);
return Ok(Some(request));
}
Err(e) => {
error!("Failed to parse JSON-RPC request: {}", e);
return Err(Error::Json(e));
}
}
}
}
pub async fn write_response(&mut self, response: JsonRpcResponse) -> Result<()> {
let json = serde_json::to_string(&response)?;
trace!("Sending response: {}", json);
self.stdout.write_all(json.as_bytes()).await?;
self.stdout.write_all(b"\n").await?;
self.stdout.flush().await?;
debug!("Sent response for id={:?}", response.id);
Ok(())
}
}
impl Default for StdioTransport {
fn default() -> Self {
Self::new()
}
}