Model Context Protocol (MCP) implementation in Rust
A Rust implementation of Anthropic's Model Context Protocol (MCP), an open standard for connecting AI assistants to data sources and tools.
⚠️ IMPORTANT NOTICE: Version 0.2.0 has been yanked due to critical issues with the SSE transport implementation. Please use version 0.2.3 instead, which includes important fixes for client-server communication, message handling, and template generation. If you're already using 0.2.0, we strongly recommend upgrading to 0.2.3 to avoid potential issues.
View Demo on Github Tools MCP Client/Server
Check out our GitHub Tools example for a complete implementation of an MCP client-server application that interacts with GitHub repositories. This example demonstrates how to build a client that can query repository READMEs and search for repositories, with support for multiple servers and client-server disconnection scenarios. It's a great starting point for understanding how to build your own MCP applications.
Add MCPR to your Cargo.toml
:
[dependencies]
mcpr = "0.2.3" # Make sure to use 0.2.3 or later, as 0.2.0 has been yanked
For CLI tools, install globally:
cargo install mcpr
The high-level client provides a simple interface for communicating with MCP servers:
use mcpr::{
client::Client,
transport::stdio::StdioTransport,
};
// Create a client with stdio transport
let transport = StdioTransport::new();
let mut client = Client::new(transport);
// Initialize the client
client.initialize()?;
// Call a tool
let request = MyToolRequest { /* ... */ };
let response: MyToolResponse = client.call_tool("my_tool", &request)?;
// Shutdown the client
client.shutdown()?;
The high-level server makes it easy to create MCP-compatible servers:
use mcpr::{
server::{Server, ServerConfig},
transport::stdio::StdioTransport,
Tool,
};
// Configure the server
let server_config = ServerConfig::new()
.with_name("My MCP Server")
.with_version("1.0.0")
.with_tool(Tool {
name: "my_tool".to_string(),
description: "My awesome tool".to_string(),
parameters_schema: serde_json::json!({
"type": "object",
"properties": {
// Tool parameters schema
},
"required": ["param1", "param2"]
}),
});
// Create the server
let mut server = Server::new(server_config);
// Register tool handlers
server.register_tool_handler("my_tool", |params| {
// Parse parameters and handle the tool call
// ...
Ok(serde_json::to_value(response)?)
})?;
// Start the server with stdio transport
let transport = StdioTransport::new();
server.start(transport)?;
MCPR includes a project generator to quickly scaffold new MCP projects with different transport types.
# Generate a project with stdio transport
mcpr generate-project --name my-stdio-project --transport stdio
# Generate a project with SSE transport
mcpr generate-project --name my-sse-project --transport sse
Each generated project includes:
my-project/
├── client/ # Client implementation
│ ├── src/
│ │ └── main.rs # Client code
│ └── Cargo.toml # Client dependencies
├── server/ # Server implementation
│ ├── src/
│ │ └── main.rs # Server code
│ └── Cargo.toml # Server dependencies
├── test.sh # Combined test script
├── test_server.sh # Server-only test script
├── test_client.sh # Client-only test script
└── run_tests.sh # Script to run all tests
When developing with generated templates, you can switch between using the published crate version and your local development version:
# In the generated Cargo.toml files (both client and server)
# For local development, uncomment this line and comment out the crates.io version:
# mcpr = { path = "/path/to/your/mcpr" }
# For production, use version from crates.io:
mcpr = "0.2.3"
This allows you to:
The template generator automatically uses the current crate version, ensuring that generated projects always reference the latest release.
# Build the server
cd my-project/server
cargo build
# Build the client
cd my-project/client
cargo build
For stdio transport, you typically run the server and pipe its output to the client:
# Run the server and pipe to client
./server/target/debug/my-stdio-project-server | ./client/target/debug/my-stdio-project-client
Or use the client to connect to the server:
# Run the server in one terminal
./server/target/debug/my-stdio-project-server
# Run the client in another terminal
./client/target/debug/my-stdio-project-client --uri "stdio://./server/target/debug/my-stdio-project-server"
For SSE transport, you run the server first, then connect with the client. The generated project includes a mock SSE transport implementation for testing:
# Run the server (default port is 8080)
./server/target/debug/my-sse-project-server --port 8080
# In another terminal, run the client
./client/target/debug/my-sse-project-client --uri "http://localhost:8080"
The SSE transport supports both interactive and one-shot modes:
# Interactive mode
./client/target/debug/my-sse-project-client --interactive
# One-shot mode
./client/target/debug/my-sse-project-client --name "Your Name"
The mock SSE transport implementation includes:
Clients support an interactive mode for manual testing:
./client/target/debug/my-project-client --interactive
Each generated project includes test scripts:
# Run all tests
./run_tests.sh
# Run only server tests
./test_server.sh
# Run only client tests
./test_client.sh
# Run the combined test (original test script)
./test.sh
MCPR supports multiple transport options:
The simplest transport, using standard input/output:
use mcpr::transport::stdio::StdioTransport;
let transport = StdioTransport::new();
Server-Sent Events transport for web-based applications:
use mcpr::transport::sse::SSETransport;
// For server
let transport = SSETransport::new("http://localhost:8080");
// For client
let transport = SSETransport::new("http://localhost:8080");
WebSocket transport for bidirectional communication is currently under development.
This section provides comprehensive instructions for generating and testing projects with both stdio and SSE transports.
When generating projects, make sure to specify the correct transport type and output directory:
# Generate a stdio project
mcpr generate-project --name test-stdio-project --transport stdio --output /tmp
# Generate an SSE project
mcpr generate-project --name test-sse-project --transport sse --output /tmp
Note: The --output
parameter specifies where to create the project directory. If omitted, the project will be created in the current directory.
Build the project:
cd /tmp/test-stdio-project
cd server && cargo build
cd ../client && cargo build
Run the server and client together:
cd /tmp/test-stdio-project
./server/target/debug/test-stdio-project-server | ./client/target/debug/test-stdio-project-client
You should see output similar to:
[INFO] Using stdio transport
[INFO] Initializing client...
[INFO] Server info: {"protocol_version":"2024-11-05","server_info":{"name":"test-stdio-project-server","version":"1.0.0"},"tools":[{"description":"A simple hello world tool","input_schema":{"properties":{"name":{"description":"Name to greet","type":"string"}},"required":["name"],"type":"object"},"name":"hello"}]}
[INFO] Running in one-shot mode with name: Default User
[INFO] Calling tool 'hello' with parameters: {"name":"Default User"}
[INFO] Received message: Hello, Default User!
Hello, Default User!
[INFO] Shutting down client
[INFO] Client shutdown complete
Run with detailed logging:
RUST_LOG=debug ./server/target/debug/test-stdio-project-server | RUST_LOG=debug ./client/target/debug/test-stdio-project-client
Run with a custom name:
./server/target/debug/test-stdio-project-server | ./client/target/debug/test-stdio-project-client --name "Your Name"
Build the project:
cd /tmp/test-sse-project
cd server && cargo build
cd ../client && cargo build
Run the server:
cd /tmp/test-sse-project/server
RUST_LOG=trace cargo run -- --port 8084 --debug
In another terminal, run the client:
cd /tmp/test-sse-project/client
RUST_LOG=trace cargo run -- --uri "http://localhost:8084" --name "Test User"
You should see output similar to:
[INFO] Using SSE transport with URI: http://localhost:8084
[INFO] Initializing client...
[INFO] Server info: {"protocol_version":"2024-11-05","server_info":{"name":"test-sse-project-server","version":"1.0.0"},"tools":[{"description":"A simple hello world tool","input_schema":{"properties":{"name":{"description":"Name to greet","type":"string"}},"required":["name"],"type":"object"},"name":"hello"}]}
[INFO] Running in one-shot mode with name: Test User
[INFO] Calling tool 'hello' with parameters: {"name":"Test User"}
[INFO] Received message: Hello, Test User!
Hello, Test User!
[INFO] Shutting down client
[INFO] Client shutdown complete
Pipe Connection Issues:
Process Termination:
Dependency Issues:
If you encounter dependency errors when building generated projects, you may need to update the Cargo.toml
files to point to your local MCPR crate (see the Local Development with Templates section):
# For local development, uncomment this line:
mcpr = { path = "/path/to/your/mcpr" }
# And comment out the crates.io version:
# mcpr = "0.2.3"
Port Already in Use:
If the SSE server fails to start with a "port already in use" error, try a different port:
./server/target/debug/test-sse-project-server --port 8085
Connection Refused:
If the client cannot connect to the server, ensure the server is running and the port is correct:
# Check if the server is listening on the port
netstat -an | grep 8084
HTTP Method Not Allowed (405):
If you see HTTP 405 errors, ensure that the server is correctly handling all required HTTP methods (GET and POST) for the SSE transport.
Client Registration Issues:
The SSE transport requires client registration before message exchange. Ensure that:
Both transport types support interactive mode for manual testing:
# For stdio transport
./client/target/debug/test-stdio-project-client --interactive
# For SSE transport
./client/target/debug/test-sse-project-client --uri "http://localhost:8084" --interactive
In interactive mode, you can:
For more advanced testing scenarios:
Testing with Multiple Clients:
The SSE transport supports multiple concurrent clients:
# Start multiple client instances in different terminals
./client/target/debug/test-sse-project-client --uri "http://localhost:8084" --name "User 1"
./client/target/debug/test-sse-project-client --uri "http://localhost:8084" --name "User 2"
Testing Error Handling:
Test how the system handles errors by sending invalid requests:
# In interactive mode, try calling a non-existent tool
> call nonexistent_tool {"param": "value"}
Performance Testing:
For performance testing, you can use tools like Apache Bench or wrk to simulate multiple concurrent clients.
Enable debug logging for detailed information:
# Set environment variable for debug logging
RUST_LOG=debug cargo run
git checkout -b feature/amazing-feature
)git commit -m 'Add some amazing feature'
)git push origin feature/amazing-feature
)This project is licensed under the MIT License - see the LICENSE file for details.
No configuration available
Related projects feature coming soon
Will recommend related projects based on sub-categories