//! MCP Transport implementations (stdio and SSE) use crate::{McpRequest, McpServer}; use anyhow::Result; use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader}; /// STDIO transport for MCP pub struct StdioTransport { server: McpServer, } impl StdioTransport { pub fn new(server: McpServer) -> Self { Self { server } } /// Run the stdio transport (reads from stdin, writes to stdout) pub async fn run(&self) -> Result<()> { let stdin = tokio::io::stdin(); let mut stdout = tokio::io::stdout(); let mut reader = BufReader::new(stdin); let mut line = String::new(); loop { line.clear(); let bytes_read = reader.read_line(&mut line).await?; if bytes_read == 0 { // EOF break; } let trimmed = line.trim(); if trimmed.is_empty() { continue; } // Parse request match serde_json::from_str::(trimmed) { Ok(request) => { // Handle request let response = self.server.handle_request(request).await; // Write response let response_json = serde_json::to_string(&response)?; stdout.write_all(response_json.as_bytes()).await?; stdout.write_all(b"\n").await?; stdout.flush().await?; } Err(e) => { eprintln!("Failed to parse request: {}", e); } } } Ok(()) } } /// SSE (Server-Sent Events) transport for MCP #[cfg(feature = "sse")] pub mod sse { use super::*; use axum::{ extract::State, response::sse::{Event, KeepAlive, Sse}, routing::{get, post}, Json, Router, }; use std::sync::Arc; use tokio_stream::StreamExt as _; pub async fn run_sse_server(server: McpServer, addr: &str) -> Result<()> { let app = Router::new() .route("/mcp", post(handle_mcp_request)) .route("/mcp/stream", get(handle_mcp_stream)) .with_state(Arc::new(server)); let listener = tokio::net::TcpListener::bind(addr).await?; axum::serve(listener, app).await?; Ok(()) } async fn handle_mcp_request( State(server): State>, Json(request): Json, ) -> Json { let response = server.handle_request(request).await; Json(response) } async fn handle_mcp_stream( State(_server): State>, ) -> Sse>> { let stream = tokio_stream::iter(vec![ Ok(Event::default().data("connected")), ]); Sse::new(stream).keep_alive(KeepAlive::default()) } }