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.
- Schema Definitions: Complete implementation of the MCP schema
- Transport Layer: Multiple transport options including stdio and SSE
- High-Level Client/Server: Easy-to-use client and server implementations
- CLI Tools: Generate server and client stubs
- Project Generator: Quickly scaffold new MCP projects
- Mock Implementations: Built-in mock transports for testing and development
- WebSocket Transport: WebSocket transport implementation is planned but not yet implemented
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:
- Test your local MCPR changes with generated projects
- Easily switch back to the stable published version
- Develop and test new features in isolation
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:
- Automatic response generation for initialization
- Echo-back functionality for tool calls
- Proper error handling and logging
- Support for all MCP message types
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:
- Ensure that the server output is properly piped to the client input
- Check for any terminal configuration that might interfere with piping
-
Process Termination:
- The server process will terminate after the client disconnects
- For long-running sessions, consider using the interactive mode
-
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:
- The client successfully registers with the server
- The client ID is properly passed in polling requests
- The server maintains the client connection state
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:
- Enter tool names and parameters manually
- Test different parameter combinations
- Observe the server's responses in real-time
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
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature
) - Commit your changes (
git commit -m 'Add some amazing feature'
) - Push to the branch (
git push origin feature/amazing-feature
) - Open a Pull Request
This project is licensed under the MIT License - see the LICENSE file for details.