Skip to main content

vtcode_core/mcp/
rmcp_transport.rs

1/// RMCP transport layer wrappers for VT Code
2///
3/// This module provides wrappers around rmcp's transport types to integrate
4/// with VT Code's configuration and error handling.
5use anyhow::{Context, Result};
6use rmcp::transport::StreamableHttpClientTransport;
7use rmcp::transport::TokioChildProcess;
8use rmcp_reqwest::header::HeaderMap;
9use std::ffi::OsString;
10use std::path::PathBuf;
11use tokio::process::Command;
12
13use vtcode_config::mcp::McpStdioServerConfig;
14
15/// Type alias for HTTP transport
16pub type HttpTransport = StreamableHttpClientTransport<rmcp_reqwest::Client>;
17
18/// Create a stdio-based transport from configuration
19///
20/// # Arguments
21/// * `stdio_config` - Stdio server configuration with command and args
22/// * `env` - Environment variables to pass to the process
23///
24/// # Returns
25/// A TokioChildProcess transport ready to use with RMCP client
26pub fn create_stdio_transport(
27    stdio_config: &McpStdioServerConfig,
28    env: &hashbrown::HashMap<OsString, OsString>,
29) -> Result<TokioChildProcess> {
30    let mut cmd = Command::new(&stdio_config.command);
31
32    // Add arguments
33    cmd.args(&stdio_config.args);
34
35    // Set working directory if specified
36    if let Some(working_dir) = &stdio_config.working_directory {
37        cmd.current_dir(working_dir);
38    }
39
40    // Configure environment variables
41    for (key, value) in env {
42        cmd.env(key, value);
43    }
44
45    // Create the child process transport
46    TokioChildProcess::new(cmd).context("Failed to create child process for MCP server")
47}
48
49/// Create a stdio transport from individual parameters (Phase 2 integration)
50///
51/// This is a convenience wrapper for use within RmcpClient where transport
52/// parameters come from different configuration sources.
53///
54/// # Arguments
55/// * `program` - Path to the executable
56/// * `args` - Command arguments
57/// * `working_dir` - Working directory (optional)
58/// * `env` - Environment variables to pass
59///
60/// # Returns
61/// A tuple of (TokioChildProcess transport, stderr reader)
62/// The stderr reader can be passed to async logging tasks
63pub fn create_stdio_transport_with_stderr(
64    program: &OsString,
65    args: &[OsString],
66    working_dir: Option<&PathBuf>,
67    env: &hashbrown::HashMap<OsString, OsString>,
68) -> Result<(TokioChildProcess, Option<tokio::process::ChildStderr>)> {
69    let mut cmd = Command::new(program);
70
71    cmd.kill_on_drop(true)
72        .stdin(std::process::Stdio::piped())
73        .stdout(std::process::Stdio::piped())
74        .stderr(std::process::Stdio::piped())
75        .env_clear();
76
77    // Add all environment variables
78    for (key, value) in env {
79        cmd.env(key, value);
80    }
81
82    // Set working directory if provided
83    if let Some(dir) = working_dir {
84        cmd.current_dir(dir);
85    }
86
87    // Add command arguments
88    cmd.args(args);
89
90    // Create transport with stderr capture for logging
91    let builder = TokioChildProcess::builder(cmd);
92    builder
93        .stderr(std::process::Stdio::piped())
94        .spawn()
95        .context("Failed to create stdio transport with stderr capture")
96}
97
98/// Create an HTTP-based transport from endpoint URL (Phase 3.2)
99///
100/// # Arguments
101/// * `endpoint` - HTTP endpoint URL (e.g., `https://api.example.com/mcp`)
102/// * `bearer_token` - Optional bearer token for authentication
103/// * `headers` - Custom HTTP headers to include in requests
104///
105/// # Returns
106/// A StreamableHttpClientTransport ready to use with RMCP client
107///
108/// # Note
109/// This is a convenience wrapper for HTTP transport creation. The actual
110/// transport construction delegates to rmcp's StreamableHttpClientTransport
111/// following the pattern used in RmcpClient::new_streamable_http_client().
112///
113/// # Example
114/// ```ignore
115/// let transport = create_http_transport(
116///     "https://api.example.com/mcp",
117///     Some("auth_token"),
118///     &HeaderMap::new()
119/// )?;
120/// ```
121pub fn create_http_transport(
122    _endpoint: &str,
123    _bearer_token: Option<&str>,
124    _headers: &HeaderMap,
125) -> Result<HttpTransport> {
126    // Phase 3.2: HTTP transport wrapper
127    // NOTE: Full implementation requires direct use of rmcp APIs
128    // See RmcpClient::new_streamable_http_client() for reference implementation
129    // This function provides the interface; actual HTTP transport is created via:
130    // StreamableHttpClientTransport::with_client(http_client, config)
131
132    anyhow::bail!(
133        "HTTP transport creation requires rmcp's StreamableHttpClientTransport. \
134         Use RmcpClient::new_streamable_http_client() for full implementation."
135    )
136}
137
138#[cfg(test)]
139mod tests {
140    #[test]
141    fn test_transport_creation() {
142        // Test transport creation with configuration
143        // Detailed tests in integration tests
144    }
145}