use anyhow::{Context, Result};
use rmcp::transport::StreamableHttpClientTransport;
use rmcp::transport::TokioChildProcess;
use rmcp_reqwest::header::HeaderMap;
use std::ffi::OsString;
use std::path::PathBuf;
use tokio::process::Command;
use vtcode_config::mcp::McpStdioServerConfig;
pub type HttpTransport = StreamableHttpClientTransport<rmcp_reqwest::Client>;
pub fn create_stdio_transport(
stdio_config: &McpStdioServerConfig,
env: &hashbrown::HashMap<OsString, OsString>,
) -> Result<TokioChildProcess> {
let mut cmd = Command::new(&stdio_config.command);
cmd.args(&stdio_config.args);
if let Some(working_dir) = &stdio_config.working_directory {
cmd.current_dir(working_dir);
}
for (key, value) in env {
cmd.env(key, value);
}
TokioChildProcess::new(cmd).context("Failed to create child process for MCP server")
}
pub fn create_stdio_transport_with_stderr(
program: &OsString,
args: &[OsString],
working_dir: Option<&PathBuf>,
env: &hashbrown::HashMap<OsString, OsString>,
) -> Result<(TokioChildProcess, Option<tokio::process::ChildStderr>)> {
let mut cmd = Command::new(program);
cmd.kill_on_drop(true)
.stdin(std::process::Stdio::piped())
.stdout(std::process::Stdio::piped())
.stderr(std::process::Stdio::piped())
.env_clear();
for (key, value) in env {
cmd.env(key, value);
}
if let Some(dir) = working_dir {
cmd.current_dir(dir);
}
cmd.args(args);
let builder = TokioChildProcess::builder(cmd);
builder
.stderr(std::process::Stdio::piped())
.spawn()
.context("Failed to create stdio transport with stderr capture")
}
pub fn create_http_transport(
_endpoint: &str,
_bearer_token: Option<&str>,
_headers: &HeaderMap,
) -> Result<HttpTransport> {
anyhow::bail!(
"HTTP transport creation requires rmcp's StreamableHttpClientTransport. \
Use RmcpClient::new_streamable_http_client() for full implementation."
)
}
#[cfg(test)]
mod tests {
#[test]
fn test_transport_creation() {
}
}