refactor: Extract shared MCP Stdio NDJSON parsing loop into mcp-stdio library

This commit is contained in:
Riz Ashraf committed 2026-09-19 07:06:14 +01:00
1 parent f8c0d58415
commit 9009f127a9
8 files changed
+77 -80

No files matched your search

+14 -45
View File
@@ -20,47 +20,7 @@ pub struct JsonRpcResponse {
pub error: Option<Value>,
}
pub async fn read_message<R: tokio::io::AsyncRead + Unpin>(
stdin: &mut BufReader<R>,
) -> Option<JsonRpcRequest> {
let mut length = 0;
loop {
let mut line = String::new();
if stdin.read_line(&mut line).await.unwrap_or(0) == 0 {
return None;
}
if line.starts_with('{') {
return match serde_json::from_str::<JsonRpcRequest>(line.trim_end()) {
Ok(req) => Some(req),
Err(e) => {
tracing::error!(
"Failed to parse JSON-RPC request from JSONL: {}. Payload: {}",
e,
line
);
None
}
};
}
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];
stdin.read_exact(&mut buffer).await.unwrap_or(0);
serde_json::from_slice(&buffer).ok()
}
pub async fn send_response(response: JsonRpcResponse) {
let msg = serde_json::to_string(&response).unwrap();
@@ -508,17 +468,25 @@ pub async fn run_mcp_loop(app_name: &str, app_version: &str) {
tracing::info!("{} MCP server started", app_name);
let mut stdin = tokio::io::BufReader::new(tokio::io::stdin());
loop {
let msg = match read_message(&mut stdin).await {
Some(m) => {
tracing::info!("Received message method: {}", m.method);
m
}
let raw_msg = match mcp_stdio::read_mcp_message(&mut stdin).await {
Some(m) => m,
None => {
tracing::info!("Stdin closed, exiting loop");
break;
}
};
let msg = match serde_json::from_str::<JsonRpcRequest>(&raw_msg) {
Ok(m) => {
tracing::info!("Received message method: {}", m.method);
m
},
Err(e) => {
tracing::error!("Failed to parse JSON-RPC request from JSONL: {}. Payload: {}", e, raw_msg);
continue;
}
};
let app_name = app_name.to_string();
let app_version = app_version.to_string();
@@ -915,3 +883,4 @@ mod tests {
assert!(req.is_none());
}
}