mcp_kit/transport/
stdio.rs1use crate::error::McpResult;
2use crate::server::{core::McpServer, session::Session};
3use futures_util::{SinkExt, StreamExt};
5use std::future::Future;
6use tokio::io::{stdin, stdout};
7use tokio_util::codec::{FramedRead, FramedWrite};
8use tracing::{debug, error};
9
10use super::codec::NdJsonCodec;
11
12pub struct StdioTransport {
14 server: McpServer,
15}
16
17impl StdioTransport {
18 pub fn new(server: McpServer) -> Self {
19 Self { server }
20 }
21
22 pub async fn serve(self) -> McpResult<()> {
23 let mut reader = FramedRead::new(stdin(), NdJsonCodec);
24 let mut writer = FramedWrite::new(stdout(), NdJsonCodec);
25 let mut session = Session::new();
26
27 tracing::info!(server = %self.server.info().name, "stdio transport started");
28
29 while let Some(msg) = reader.next().await {
30 match msg {
31 Ok(msg) => {
32 debug!(?msg, "Received message");
33 if let Some(response) = self.server.handle_message(msg, &mut session).await {
34 debug!(?response, "Sending response");
35 if let Err(e) = writer.send(response).await {
36 error!(error = %e, "Failed to write response");
37 break;
38 }
39 }
40 }
41 Err(e) => {
42 error!(error = %e, "Failed to decode message");
43 }
44 }
45 }
46
47 tracing::info!("stdio transport closed");
48 Ok(())
49 }
50}
51
52pub trait ServeStdioExt {
54 fn serve_stdio(self) -> impl Future<Output = McpResult<()>> + Send;
55}
56
57impl ServeStdioExt for McpServer {
58 fn serve_stdio(self) -> impl Future<Output = McpResult<()>> + Send {
59 StdioTransport::new(self).serve()
60 }
61}