A comprehensive Rust implementation of the Model Context Protocol (MCP) client. This project provides a robust, type-safe foundation for building AI applications that can interact with MCP-compatible servers.
- Features
- Prerequisites
- Installation
- Quick Start
- Architecture
- Usage Examples
- API Documentation
- Configuration
- Security
- Troubleshooting
- Contributing
- License
- β Full MCP Protocol Support - Complete implementation of JSON-RPC 2.0 based MCP
- β Type-Safe Client - Leverages Rust's type system for compile-time safety
- β Async/Await - Fully asynchronous using Tokio runtime
- β Multi-Server Support - Manage multiple MCP server connections simultaneously
- β Tool Management - Discover, validate, and execute server-exposed tools
- β Resource Access - Read and manage resources from MCP servers
- β Prompt Support - Utilize pre-defined LLM prompts from servers
- π Input Validation - Comprehensive input validation and sanitization
- π Error Isolation - Secure error handling preventing information leakage
- π Logging & Debugging - Comprehensive structured logging system
- π Reconnection Logic - Automatic reconnection with exponential backoff
- π οΈ Tool Execution - Execute MCP tools with validation and error handling
- π± Streaming Support - Handle streaming responses for long-running operations
- Rust: 1.70 or later (Install Rust)
- Operating System: macOS, Linux, or Windows
# Check Rust installation
rustc --version
cargo --versiongit clone https://github.com/yourusername/mcp-client-rust.git
cd mcp-client-rust# Update Rust toolchain
rustup update
# Build the project
cargo build --releaseCreate a .env file in the project root:
# Logging
LOG_LEVEL=info
LOG_FILE=./mcp-client.log
# MCP Configuration
MCP_TIMEOUT_SECONDS=30use mcp_client_rust::client::MCPClient;
use mcp_client_rust::transport::StdioTransport;
use mcp_client_rust::types::ClientInfo;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Initialize MCP client
let transport = Box::new(StdioTransport::new("./mcp-server", &[])?);
let client_info = ClientInfo {
name: "MyClient".to_string(),
version: "1.0.0".to_string(),
};
let mut client = MCPClient::new(transport, client_info);
client.initialize().await?;
// List tools
let tools = client.list_tools().await?;
for tool in tools {
println!("Tool: {} - {}", tool.name, tool.description.unwrap_or_default());
}
// Call a tool
let result = client.call_tool(
"greet",
serde_json::json!({
"name": "Alice"
})
).await?;
println!("Result: {:?}", result);
client.close().await?;
Ok(())
}mcp-client-rust/
βββ src/
β βββ lib.rs # Library entry point
β βββ types.rs # MCP type definitions
β βββ transport.rs # Transport layer (Stdio, HTTP/SSE)
β βββ client.rs # Core MCP client
β βββ tool_manager.rs # Tool management and validation
β βββ multi_server.rs # Multi-server connection manager
β βββ security.rs # Security policies and validation
β βββ logging.rs # Logging utilities
β βββ validation.rs # Input validation
β βββ errors.rs # Error types
βββ examples/
β βββ basic_example.rs
β βββ multi_server_example.rs
βββ tests/
β βββ integration_tests.rs
βββ Cargo.toml
βββ README.md
βββ .env.example
use mcp_client_rust::client::MCPClient;
use mcp_client_rust::transport::StdioTransport;
use mcp_client_rust::types::ClientInfo;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Create transport to connect to the server
let transport = Box::new(StdioTransport::new(
"/Users/sudhirkumar/Desktop/sudhir/gitsudhir/mcp-server-rust/target/release/mcp-server-rust",
&[]
)?);
let client_info = ClientInfo {
name: "TestClient".to_string(),
version: "1.0.0".to_string(),
};
let mut client = MCPClient::new(transport, client_info);
client.initialize().await?;
// List available tools
let tools = client.list_tools().await?;
println!("Available tools:");
for tool in tools {
println!("- {} ({})", tool.name, tool.description.unwrap_or_default());
}
client.close().await?;
Ok(())
}use mcp_client_rust::client::MCPClient;
use serde_json::json;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut client = create_client().await?;
// Execute a greeting tool
let result = client.call_tool(
"greet",
json!({
"name": "Alice"
})
).await?;
match &result.content[0] {
mcp_client_rust::types::ToolResultContent::Text { text } => {
println!("Greeting result: {}", text);
}
_ => println!("Received non-text result"),
}
client.close().await?;
Ok(())
}
async fn create_client() -> Result<MCPClient, Box<dyn std::error::Error>> {
let transport = Box::new(StdioTransport::new(
"/Users/sudhirkumar/Desktop/sudhir/gitsudhir/mcp-server-rust/target/release/mcp-server-rust",
&[]
)?);
let client_info = mcp_client_rust::types::ClientInfo {
name: "TestClient".to_string(),
version: "1.0.0".to_string(),
};
let mut client = MCPClient::new(transport, client_info);
client.initialize().await?;
Ok(client)
}#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut client = create_client().await?;
// Read a resource
let content = client.read_resource("config://app").await?;
for item in content.contents {
match item {
mcp_client_rust::types::ContentItem::Text { text } => {
println!("Content: {}", text);
}
mcp_client_rust::types::ContentItem::Blob { blob } => {
println!("Binary data: {} bytes", blob.len());
}
}
}
client.close().await?;
Ok(())
}The main client for interacting with MCP servers.
impl MCPClient {
// Initialize connection with server
pub async fn initialize(&mut self) -> ClientResult<()>
// List available tools
pub async fn list_tools(&mut self) -> ClientResult<Vec<Tool>>
// List available resources
pub async fn list_resources(&mut self)
-> ClientResult<(Vec<Resource>, Vec<ResourceTemplate>)>
// List available prompts
pub async fn list_prompts(&mut self) -> ClientResult<Vec<Prompt>>
// Execute a tool
pub async fn call_tool(
&mut self,
tool_name: &str,
arguments: Value
) -> ClientResult<ToolResult>
// Read a resource
pub async fn read_resource(&mut self, uri: &str)
-> ClientResult<ResourceContent>
// Get a prompt with arguments
pub async fn get_prompt(
&mut self,
name: &str,
arguments: Option<HashMap<String, String>>
) -> ClientResult<PromptsResult>
// Close connection
pub async fn close(&mut self) -> ClientResult<()>
}Create a .env file in the project root:
# Logging Configuration
LOG_LEVEL=info
LOG_FILE=./mcp-client.log
# MCP Configuration
MCP_TIMEOUT_SECONDS=30
MCP_MAX_RETRIES=3-
Validate All Inputs
use mcp_client_rust::validation::InputValidator; if !InputValidator::validate_file_path(user_path) { return Err("Invalid file path".into()); }
-
Comprehensive Logging
let logger = mcp_client_rust::logging::McpLogger::new(mcp_client_rust::logging::LogLevel::Info) .with_file("./mcp-client.log".to_string()); logger.info("Tool execution attempt"); logger.error("Unauthorized access");
Problem: Cannot connect to MCP server
Solutions:
// Verify server path exists
let path = "/Users/sudhirkumar/Desktop/sudhir/gitsudhir/mcp-server-rust/target/release/mcp-server-rust";
if !std::path::Path::new(path).exists() {
eprintln!("Server executable not found at: {}", path);
}
// Check server permissions
#[cfg(unix)]
std::fs::set_permissions(path, std::fs::Permissions::from_mode(0o755))?;Problem: "Request timeout" errors
Solutions:
# Increase timeout
MCP_TIMEOUT_SECONDS=60# Clone repository
git clone https://github.com/yourusername/mcp-client-rust.git
cd mcp-client-rust
# Build debug version
cargo build
# Build release version (optimized)
cargo build --release
# Run tests
cargo test
# Run with logging
RUST_LOG=debug cargo run --example basic_example# Run all tests
cargo test
# Run specific test
cargo test test_name
# Run with output
cargo test -- --nocaptureAll examples are located in the examples/ directory:
- basic_example - Simple tool execution
- multi_server_example - Managing multiple MCP servers
Run any example:
cargo run --example <example_name>Contributions are welcome! Please follow these steps:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
- Follow Rust naming conventions
- Use
cargo fmtfor formatting - Run
cargo clippyfor linting - Add tests for new features
- Update documentation
This project is licensed under the MIT License - see the LICENSE file for details.
For help and questions:
- Check Troubleshooting section
- Search existing GitHub Issues
- Create a new issue with detailed information
- Model Context Protocol team for the specification
- Rust community for amazing libraries and support
Last Updated: 2026-02-13
Version: 0.1.0
Made with β€οΈ in Rust