pub struct ProcessTransport { /* private fields */ }
Expand description
Process-based MCP transport using stdin/stdout communication
Provides communication with local MCP servers running as separate processes using JSON-RPC 2.0 over stdin/stdout pipes. This transport is ideal for local tools, development servers, and sandboxed environments where you need process isolation and direct control over the MCP server lifecycle.
§Features
- Process Isolation: Each MCP server runs in its own process for security
- No Network Overhead: Direct pipe communication for maximum performance
- Environment Control: Full control over working directory and environment variables
- Resource Management: Automatic process cleanup and lifecycle management
- Synchronous Communication: Request/response correlation over stdin/stdout
- Error Handling: Comprehensive process and communication error handling
§Use Cases
- Local Development: Running MCP servers during development and testing
- Filesystem Tools: Local file operations and system utilities
- Sandboxed Execution: Isolated execution environments for security
- Custom Tools: Private or proprietary MCP servers
- CI/CD Integration: Running MCP servers in automated environments
§Example Usage
use mistralrs_mcp::transport::{ProcessTransport, McpTransport};
use std::collections::HashMap;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
// Basic process transport
let transport = ProcessTransport::new(
"mcp-server-filesystem".to_string(),
vec!["--root".to_string(), "/tmp".to_string()],
None,
None
).await?;
// With custom working directory and environment
let mut env = HashMap::new();
env.insert("MCP_LOG_LEVEL".to_string(), "debug".to_string());
env.insert("MCP_TIMEOUT".to_string(), "30".to_string());
let transport = ProcessTransport::new(
"/usr/local/bin/my-mcp-server".to_string(),
vec!["--config".to_string(), "production.json".to_string()],
Some("/opt/mcp-server".to_string()), // Working directory
Some(env) // Environment variables
).await?;
// Use the transport for MCP communication
let result = transport.send_request("tools/list", serde_json::Value::Null).await?;
println!("Available tools: {}", result);
Ok(())
}
§Process Management
The transport automatically manages the child process lifecycle:
- Spawns the process with configured arguments and environment
- Sets up stdin/stdout pipes for JSON-RPC communication
- Monitors process health and handles crashes
- Cleans up resources when the transport is dropped or closed
§Communication Protocol
Uses JSON-RPC 2.0 over stdin/stdout with line-delimited messages:
- Each request is a single line of JSON sent to stdin
- Each response is a single line of JSON read from stdout
- Stderr is captured for debugging and error reporting
Implementations§
Source§impl ProcessTransport
impl ProcessTransport
Sourcepub async fn new(
command: String,
args: Vec<String>,
work_dir: Option<String>,
env: Option<HashMap<String, String>>,
) -> Result<Self>
pub async fn new( command: String, args: Vec<String>, work_dir: Option<String>, env: Option<HashMap<String, String>>, ) -> Result<Self>
Creates a new process transport by spawning an MCP server process
This constructor spawns a new process with the specified command, arguments, and environment, then sets up stdin/stdout pipes for JSON-RPC communication. The process is ready to receive MCP requests immediately after creation.
§Arguments
command
- The command to execute (e.g., “mcp-server-filesystem”, “/usr/bin/python”)args
- Command-line arguments to pass to the processwork_dir
- Optional working directory for the process (defaults to current directory)env
- Optional environment variables to set for the process
§Returns
A configured ProcessTransport with the spawned process ready for communication
§Errors
- Command not found or not executable
- Permission denied errors
- Process spawn failures
- Pipe setup errors (stdin/stdout/stderr)
- Working directory access errors
§Example
use mistralrs_mcp::transport::ProcessTransport;
use std::collections::HashMap;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
// Simple filesystem server
let transport = ProcessTransport::new(
"mcp-server-filesystem".to_string(),
vec!["--root".to_string(), "/home/user/documents".to_string()],
None,
None
).await?;
// Python-based MCP server with custom environment
let mut env = HashMap::new();
env.insert("PYTHONPATH".to_string(), "/opt/mcp-servers".to_string());
env.insert("MCP_DEBUG".to_string(), "1".to_string());
let transport = ProcessTransport::new(
"python".to_string(),
vec!["-m".to_string(), "my_mcp_server".to_string(), "--port".to_string(), "8080".to_string()],
Some("/opt/mcp-servers".to_string()),
Some(env)
).await?;
Ok(())
}
Trait Implementations§
Source§impl McpTransport for ProcessTransport
impl McpTransport for ProcessTransport
Source§fn send_request<'life0, 'life1, 'async_trait>(
&'life0 self,
method: &'life1 str,
params: Value,
) -> Pin<Box<dyn Future<Output = Result<Value>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn send_request<'life0, 'life1, 'async_trait>(
&'life0 self,
method: &'life1 str,
params: Value,
) -> Pin<Box<dyn Future<Output = Result<Value>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Sends an MCP request to the child process and returns the response
This method implements JSON-RPC 2.0 over stdin/stdout pipes. It sends a line-delimited JSON request to the process stdin and reads the corresponding response from stdout. Communication is synchronous with proper request/response correlation.
§Arguments
method
- The MCP method name (e.g., “tools/list”, “tools/call”, “resources/read”)params
- JSON parameters for the method call
§Returns
The result portion of the JSON-RPC response
§Errors
- Process communication errors (broken pipes)
- Process crashes or unexpected termination
- JSON serialization/deserialization errors
- MCP server errors (returned in JSON-RPC error field)
- I/O errors on stdin/stdout
§Example
use mistralrs_mcp::transport::{ProcessTransport, McpTransport};
use serde_json::json;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let transport = ProcessTransport::new(
"mcp-server-filesystem".to_string(),
vec!["--root".to_string(), "/tmp".to_string()],
None,
None
).await?;
// List available tools
let tools = transport.send_request("tools/list", serde_json::Value::Null).await?;
// Call a specific tool
let params = json!({
"name": "read_file",
"arguments": {"path": "/tmp/example.txt"}
});
let result = transport.send_request("tools/call", params).await?;
Ok(())
}
Source§fn ping<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn ping<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Tests the process connection by sending a ping request
Sends a “ping” method call to verify that the MCP server process is responsive and the stdin/stdout communication is working properly.
§Returns
Ok(()) if the ping was successful
§Errors
- Process communication errors
- Process crashed or terminated
- Broken stdin/stdout pipes
Source§fn close<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn close<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Terminates the child process and cleans up resources
This method forcefully terminates the MCP server process and closes all associated pipes. Any pending requests will fail after this call. The transport cannot be used after closing.
§Returns
Ok(()) if the process was terminated successfully
§Errors
- Process termination errors
- Resource cleanup failures
§Note
This method sends SIGKILL to the process, which may not allow for graceful cleanup. Consider implementing graceful shutdown through MCP protocol methods before calling this method.
Auto Trait Implementations§
impl Freeze for ProcessTransport
impl !RefUnwindSafe for ProcessTransport
impl Send for ProcessTransport
impl Sync for ProcessTransport
impl Unpin for ProcessTransport
impl !UnwindSafe for ProcessTransport
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self
into a Left
variant of Either<Self, Self>
if into_left
is true
.
Converts self
into a Right
variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self
into a Left
variant of Either<Self, Self>
if into_left(&self)
returns true
.
Converts self
into a Right
variant of Either<Self, Self>
otherwise. Read more