Struct ProcessTransport

Source
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

Source

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 process
  • work_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

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,

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,

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,

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§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<T> Instrument for T

§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided [Span], returning an Instrumented wrapper. Read more
§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts 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 more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts 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
§

impl<T> PolicyExt for T
where T: ?Sized,

§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns [Action::Follow] only if self and other return Action::Follow. Read more
§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns [Action::Follow] if either self or other returns Action::Follow. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

§

fn vzip(self) -> V

§

impl<T> WithSubscriber for T

§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a [WithDispatch] wrapper. Read more
§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a [WithDispatch] wrapper. Read more
§

impl<T> ErasedDestructor for T
where T: 'static,

§

impl<T> Ungil for T
where T: Send,