From 5f690f4b74bca622b311378639ae70f264a857c0 Mon Sep 17 00:00:00 2001 From: iamdoubz <> Date: Tue, 7 Jul 2026 00:21:16 -0500 Subject: [PATCH] feat(mcp): stdio transport adapter (T10.4, FR-MCP-6) serve_once() runs one MCP session over the current process's stdin/ stdout to completion -- the entry point main.rs's --mcp-stdio flag calls into (next commit). No bearer-token check here: spawning this process at all requires the same local-user privilege as any other command, so process-spawn capability is the trust boundary for stdio, not a header. --- src-tauri/src/mcp/stdio_transport.rs | 31 ++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 src-tauri/src/mcp/stdio_transport.rs diff --git a/src-tauri/src/mcp/stdio_transport.rs b/src-tauri/src/mcp/stdio_transport.rs new file mode 100644 index 0000000..3447cf6 --- /dev/null +++ b/src-tauri/src/mcp/stdio_transport.rs @@ -0,0 +1,31 @@ +//! stdio transport (FR-MCP-6) — "a thin adapter the agent spawns". A coding +//! agent's MCP client config spawns `whispassist.exe --mcp-stdio` and talks +//! JSON-RPC over that child process's stdin/stdout; `main.rs` checks for that +//! flag before building the Tauri window and calls `serve_once` here instead. +//! +//! There is no bearer-token header to check here (unlike HTTP): the ability +//! to spawn this process at all already requires the same OS-level privilege +//! as running any other local command as the signed-in user, so process-spawn +//! capability is the trust boundary for stdio, same as other local-only MCP +//! servers. `set_mcp_enabled` still mints/stores a token (`mcp::token`) for +//! parity with the HTTP transport and in case a future stdio client wants to +//! pass it, but this transport does not require presenting it. + +use crate::mcp::handler::WaMcpHandler; +use crate::mcp::McpError; +use rmcp::ServiceExt; + +/// Serves one MCP session over the current process's stdin/stdout until the +/// peer disconnects, then returns. +pub async fn serve_once(handler: WaMcpHandler) -> Result<(), McpError> { + let transport = rmcp::transport::io::stdio(); + let running = handler + .serve(transport) + .await + .map_err(|e| McpError::Server(e.to_string()))?; + running + .waiting() + .await + .map_err(|e| McpError::Server(e.to_string()))?; + Ok(()) +}