Implementation Guides
MCP-RS Implementation Guides
Step-by-step guides for implementing and using MCP-RS.
Quick Start Guides
- WordPress Integration - Complete WordPress REST API integration with media management
- Database Integration - Multi-engine database setup and configuration
- Security Setup - Enterprise-grade security configuration
- Custom Handler Development - Create your own MCP handlers
- Configuration Guide - Configure MCP-RS for your environment
Getting Started
Installation and Setup
1. Project Setup
Create a new Rust project and add MCP-RS as a dependency:
cargo new my-mcp-server
cd my-mcp-server
Add to Cargo.toml:
[dependencies]
mcp-rs = "0.1.0"
tokio = { version = "1.0", features = ["full"] }
serde_json = "1.0"
2. Basic Server Implementation
Create a basic MCP server in src/main.rs:
use mcp_rs::{
server::McpServer,
config::Config,
handlers::wordpress::WordPressHandler,
mcp::McpHandler,
};
use std::collections::HashMap;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Initialize logging
tracing_subscriber::init();
// Load configuration
let config = Config::load("mcp-config.toml")?;
// Create server
let mut server = McpServer::new();
// Add WordPress handler if configured
if let Some(wp_config) = config.wordpress {
let handler = WordPressHandler::new(wp_config);
server.add_handler("wordpress", Box::new(handler));
}
// Start server
let address = config.server.address();
println!("Starting MCP server on {}", address);
server.serve(address).await?;
Ok(())
}
3. Configuration File
Create mcp-config.toml:
[server]
host = "127.0.0.1"
port = 3000
# WordPress handler configuration (optional)
[wordpress]
url = "https://your-wordpress-site.com"
username = "your_username"
password = "your_application_password"
timeout_seconds = 30
WordPress Integration Guide
1. WordPress Setup
Generate Application Password
- Log into your WordPress admin dashboard
- Go to Users → Profile
- Scroll to Application Passwords section
- Enter application name (e.g., “MCP-RS”)
- Click Add New Application Password
- Copy the generated password
Configure WordPress Handler
Update mcp-config.toml:
[server]
host = "127.0.0.1"
port = 8080
[wordpress]
url = "https://your-wordpress-site.com"
username = "your_username"
password = "your_application_password_here"
timeout_seconds = 30
log_level = “info”
[handlers.wordpress] url = “https://your-wordpress-site.com” username = “your-username” password = “generated-app-password” enabled = true
### 2. WordPress Handler Implementation
Create a custom server with WordPress integration:
```rust
use mcp_rs::{
McpServer,
config::Config,
handlers::wordpress::WordPressHandler,
protocol::BasicMcpProtocol,
};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
tracing_subscriber::init();
// Load configuration
let config = Config::load()?;
// Create protocol
let mut protocol = BasicMcpProtocol::new("wordpress-server", "1.0.0");
// Add WordPress handler if enabled
if let Some(wp_config) = config.handlers.wordpress {
if wp_config.enabled {
let wp_handler = WordPressHandler::new(wp_config).await?;
protocol.add_handler("wordpress", Box::new(wp_handler));
}
}
// Start server
let server = McpServer::new(protocol);
let bind_addr = config.server.bind_addr.parse()?;
println!("Starting WordPress MCP server on {}", bind_addr);
server.serve(bind_addr).await?;
Ok(())
}
3. Using WordPress Tools
Get Posts
{
"jsonrpc": "2.0",
"method": "tools/call",
"params": {
"name": "wordpress_get_posts",
"arguments": {
"per_page": 5,
"status": "publish"
}
},
"id": 1
}
Create a Post
{
"jsonrpc": "2.0",
"method": "tools/call",
"params": {
"name": "wordpress_create_post",
"arguments": {
"title": "My New Post",
"content": "<p>This is the post content.</p>",
"status": "draft"
}
},
"id": 2
}
Environment Health Check
Before using WordPress tools, validate your environment:
{
"jsonrpc": "2.0",
"method": "tools/call",
"params": {
"name": "wordpress_health_check",
"arguments": {}
},
"id": 3
}
Response Example:
{
"jsonrpc": "2.0",
"result": {
"content": [{
"type": "text",
"text": "WordPress Health Check Report\n\n✅ Status: healthy\n\n🌐 Site Information:\n- URL: https://your-site.com\n- Name: Your Site Name\n- Version: 6.3.2\n\n👤 User Information:\n- Username: admin\n- Display Name: Site Administrator\n- Roles: administrator\n\n🔐 Capabilities:\n- publish_posts: ✅\n- upload_files: ✅\n- edit_posts: ✅\n\n📁 Media Upload:\n- Status: ✅ Supported\n- Max Upload Size: 64M\n\n⚡ Performance:\n- Site Response: 245ms\n- API Response: 89ms\n\n✅ All systems operational! WordPress is ready for MCP operations."
}],
"is_error": false
},
"id": 3
}
Upload Media with Featured Image
{
"jsonrpc": "2.0",
"method": "tools/call",
"params": {
"name": "wordpress_upload_media",
"arguments": {
"file_data": "iVBORw0KGgoAAAANSUhEUgAA...",
"filename": "featured-image.jpg",
"mime_type": "image/jpeg"
}
},
"id": 4
}
Then use the returned media ID to create a post:
{
"jsonrpc": "2.0",
"method": "tools/call",
"params": {
"name": "wordpress_create_post_with_featured_image",
"arguments": {
"title": "Post with Featured Image",
"content": "<p>This post has a beautiful featured image.</p>",
"featured_media_id": 123
}
},
"id": 5
}
4. Production Workflow
Pre-Production Checklist
- Environment Validation
# Run health check example cargo run --example wordpress_health_check - Configuration Verification
- Verify WordPress URL is accessible
- Test application password authentication
- Check user permissions are sufficient
- Functional Testing
- Test post creation and retrieval
- Verify media upload capabilities
- Confirm featured image functionality
Monitoring and Maintenance
- Regular Health Checks: Schedule periodic environment validation
- Performance Monitoring: Track API response times and success rates
- Error Handling: Implement proper error logging and alerting
- Backup Procedures: Ensure WordPress content is properly backed up
Custom Handler Development
1. Implement the McpHandler Trait
use async_trait::async_trait;
use mcp_rs::{
protocol::McpHandler,
types::{Tool, Resource, CallToolResult},
Error, Result,
};
use serde_json::Value;
pub struct MyCustomHandler {
// Handler configuration and state
}
#[async_trait]
impl McpHandler for MyCustomHandler {
async fn list_tools(&self) -> Result<Vec<Tool>> {
Ok(vec![
Tool {
name: "my_custom_tool".to_string(),
description: "A custom tool implementation".to_string(),
input_schema: Some(serde_json::json!({
"type": "object",
"properties": {
"input": {"type": "string"}
}
})),
}
])
}
async fn call_tool(&self, name: &str, args: Option<Value>) -> Result<CallToolResult> {
match name {
"my_custom_tool" => {
let input = args
.and_then(|v| v.get("input"))
.and_then(|v| v.as_str())
.unwrap_or("default");
// Implement your tool logic here
let result = format!("Processed: {}", input);
Ok(CallToolResult {
content: vec![serde_json::json!({
"type": "text",
"text": result
})],
is_error: false,
})
}
_ => Err(Error::MethodNotFound(name.to_string())),
}
}
async fn list_resources(&self) -> Result<Vec<Resource>> {
// Implement resource listing
Ok(vec![])
}
async fn read_resource(&self, uri: &str) -> Result<String> {
// Implement resource reading
Err(Error::ResourceNotFound(uri.to_string()))
}
}
2. Register the Handler
// Add to your server setup
let custom_handler = MyCustomHandler::new();
protocol.add_handler("custom", Box::new(custom_handler));
Configuration Management
1. Configuration Structure
use serde::{Deserialize, Serialize};
#[derive(Debug, Deserialize, Serialize)]
pub struct MyConfig {
pub server: ServerConfig,
pub my_handler: MyHandlerConfig,
}
#[derive(Debug, Deserialize, Serialize)]
pub struct MyHandlerConfig {
pub api_key: String,
pub endpoint: String,
pub timeout: u64,
pub enabled: bool,
}
2. Environment Variable Overrides
Set environment variables to override configuration:
export MCP_SERVER_BIND_ADDR="0.0.0.0:8080"
export MCP_MY_HANDLER_API_KEY="your-api-key"
export MCP_MY_HANDLER_ENABLED="true"
3. Loading Configuration
use mcp_rs::config::Config;
// Load from file with environment overrides
let config = Config::load_from_file("config.toml")?;
// Or load from default locations
let config = Config::load()?;
Error Handling Best Practices
1. Custom Error Types
use thiserror::Error;
#[derive(Error, Debug)]
pub enum MyHandlerError {
#[error("API request failed: {0}")]
ApiError(String),
#[error("Invalid configuration: {0}")]
ConfigError(String),
#[error("Timeout after {0}s")]
Timeout(u64),
}
// Convert to MCP Error
impl From<MyHandlerError> for mcp_rs::Error {
fn from(err: MyHandlerError) -> Self {
mcp_rs::Error::InternalError(err.to_string())
}
}
2. Error Handling in Tools
async fn call_tool(&self, name: &str, args: Option<Value>) -> Result<CallToolResult> {
match name {
"my_tool" => {
match self.execute_tool(args).await {
Ok(result) => Ok(CallToolResult {
content: vec![serde_json::json!({
"type": "text",
"text": result
})],
is_error: false,
}),
Err(e) => Ok(CallToolResult {
content: vec![serde_json::json!({
"type": "text",
"text": format!("Error: {}", e)
})],
is_error: true,
}),
}
}
_ => Err(Error::MethodNotFound(name.to_string())),
}
}
Testing
1. Unit Testing Handlers
#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;
#[tokio::test]
async fn test_my_custom_tool() {
let handler = MyCustomHandler::new();
let result = handler.call_tool(
"my_custom_tool",
Some(json!({"input": "test"}))
).await.unwrap();
assert!(!result.is_error);
// Add more assertions
}
}
2. Integration Testing
#[tokio::test]
async fn test_server_integration() {
// Start test server
let protocol = BasicMcpProtocol::new("test", "1.0.0");
let server = McpServer::new(protocol);
// Test with HTTP client
// Add integration test logic
}
Performance Optimization
1. Connection Pooling
use reqwest::Client;
use std::sync::Arc;
pub struct OptimizedHandler {
client: Arc<Client>,
}
impl OptimizedHandler {
pub fn new() -> Self {
let client = Client::builder()
.timeout(Duration::from_secs(30))
.pool_max_idle_per_host(10)
.build()
.unwrap();
Self {
client: Arc::new(client),
}
}
}
2. Caching
use std::collections::HashMap;
use std::sync::RwLock;
pub struct CachedHandler {
cache: RwLock<HashMap<String, (String, std::time::Instant)>>,
cache_duration: Duration,
}
impl CachedHandler {
async fn get_cached_or_fetch(&self, key: &str) -> Result<String> {
// Check cache first
{
let cache = self.cache.read().unwrap();
if let Some((value, timestamp)) = cache.get(key) {
if timestamp.elapsed() < self.cache_duration {
return Ok(value.clone());
}
}
}
// Fetch and cache
let value = self.fetch_data(key).await?;
{
let mut cache = self.cache.write().unwrap();
cache.insert(key.to_string(), (value.clone(), std::time::Instant::now()));
}
Ok(value)
}
}
Deployment
1. Docker Deployment
Create Dockerfile:
FROM rust:1.70 AS builder
WORKDIR /app
COPY . .
RUN cargo build --release
FROM debian:bookworm-slim
RUN apt-get update && apt-get install -y ca-certificates && rm -rf /var/lib/apt/lists/*
COPY --from=builder /app/target/release/my-mcp-server /usr/local/bin/
COPY --from=builder /app/mcp-config.toml /etc/mcp/
EXPOSE 8080
CMD ["my-mcp-server"]
2. Systemd Service
Create /etc/systemd/system/mcp-rs.service:
[Unit]
Description=MCP-RS Server
After=network.target
[Service]
Type=simple
User=mcp
WorkingDirectory=/opt/mcp-rs
ExecStart=/opt/mcp-rs/mcp-rs
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
3. Environment Configuration
Production environment variables:
export MCP_SERVER_BIND_ADDR="0.0.0.0:8080"
export MCP_SERVER_LOG_LEVEL="warn"
export RUST_LOG="warn"
Configuration Guide
This section provides comprehensive configuration options for MCP-RS.
Environment Variables
MCP-RS supports environment variable expansion in configuration files using the ${VAR_NAME} syntax:
[handlers.wordpress]
url = "${WORDPRESS_URL}"
username = "${WORDPRESS_USERNAME}"
password = "${WORDPRESS_PASSWORD}"
Core Environment Variables
| Variable | Description | Default | Example |
|---|---|---|---|
MCP_SERVER_BIND_ADDR |
Server bind address | 127.0.0.1:8080 |
0.0.0.0:3000 |
MCP_SERVER_LOG_LEVEL |
Logging level | info |
debug, warn, error |
RUST_LOG |
Rust logging configuration | info |
mcp_rs=debug |
WordPress Integration Variables
| Variable | Description | Required | Example |
|---|---|---|---|
WORDPRESS_URL |
WordPress site URL | Yes | https://example.com |
WORDPRESS_USERNAME |
WordPress username | Yes | admin |
WORDPRESS_PASSWORD |
Application password | Yes | xxxx xxxx xxxx xxxx xxxx xxxx |
Security Configuration
Rate Limiting
[handlers.wordpress.rate_limit]
max_requests_per_minute = 60
burst_size = 10
enabled = true
Timeout Settings
[handlers.wordpress]
timeout_seconds = 30
retry_attempts = 3
retry_delay_ms = 1000
Deployment Configurations
Development
[server]
bind_addr = "127.0.0.1:8080"
log_level = "debug"
[handlers.wordpress]
timeout_seconds = 60 # Longer timeout for debugging
Production
[server]
bind_addr = "0.0.0.0:8080"
log_level = "warn"
[handlers.wordpress]
timeout_seconds = 30
rate_limit.enabled = true
rate_limit.max_requests_per_minute = 100
Docker
[server]
bind_addr = "0.0.0.0:8080"
log_level = "info"
# Use environment variables for sensitive data
[handlers.wordpress]
url = "${WORDPRESS_URL}"
username = "${WORDPRESS_USERNAME}"
password = "${WORDPRESS_PASSWORD}"
For more advanced topics and API reference, see the API Documentation.