Turul MCP Framework
A comprehensive, battle-tested Rust framework for building Model Context Protocol (MCP) servers and clients with modern patterns, extensive tooling, and enterprise-grade features. Fully compliant with MCP 2025-11-25 specification.
Ask AI about Turul MCP Framework
Powered by Claude Β· Grounded in docs
I know everything about Turul MCP Framework. Ask me about installation, configuration, usage, or troubleshooting.
0/500
Reviews
Documentation
Turul MCP Framework - Beta Rust Implementation
A comprehensive Rust framework for building Model Context Protocol (MCP) servers and clients with modern patterns, extensive tooling, and enterprise-grade features. Fully compliant with MCP 2025-11-25 specification.
β οΈ Beta Status - Active development with ongoing feature enhancements. Full MCP 2025-11-25 compliance including task storage and runtime. Suitable for development and testing.
π§ͺ Active Development - Comprehensive Test Coverage
1729+ passing tests across workspace β’ Complete async SessionContext integration β’ Framework-native testing patterns
β¨ Key Highlights
- ποΈ 13 Framework Crates: Complete MCP ecosystem with core framework, client library, task storage, and serverless support
- π 58 Comprehensive Examples: Real-world business applications and framework demonstration examples (all validated through comprehensive testing campaign)
- π§ͺ 1729+ Development Tests: Comprehensive test suite with core framework tests, SessionContext integration tests, and framework-native integration tests
- β‘ Multiple Development Patterns: Derive macros, function attributes, declarative macros, and manual implementation
- π Transport Flexibility: Streamable HTTP via StreamableHttpHandler with SSE streaming (stdio planned)
- βοΈ Serverless Support: AWS Lambda integration with streaming responses and SQS event processing
- π§ Development Features: Session management, real-time notifications, performance monitoring, and UUID v7 support
- β‘ Performance Optimized: Comprehensive benchmarking suite with >1000 RPS throughput, <100ms response times, and extensive stress testing
π Quick Start
1. Function Macros (Simplest - Recommended)
use turul_mcp_derive::mcp_tool;
use turul_mcp_server::prelude::*;
#[mcp_tool(name = "add", description = "Add two numbers")]
async fn add(
#[param(description = "First number")] a: f64,
#[param(description = "Second number")] b: f64,
) -> McpResult<f64> {
Ok(a + b) // Framework wraps as {"output": 8.0} in JSON-RPC response
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let server = McpServer::builder()
.name("calculator-server")
.version("1.0.0")
.tool_fn(add) // Use function name directly
.bind_address("127.0.0.1:8641".parse()?) // Default port; customize as needed
.build()?;
server.run().await
}
Task support: Add
task_support = "optional"to enable the "Run as Task" button in MCP Inspector. Values:"optional","required","forbidden". Requires.with_task_storage()on the server builder.
2. Derive Macros (Struct-Based)
use turul_mcp_derive::McpTool;
use turul_mcp_server::prelude::*;
#[derive(McpTool, Clone)]
#[tool(name = "calculator", description = "Mathematical operations")]
struct Calculator {
#[param(description = "First number")]
a: f64,
#[param(description = "Second number")]
b: f64,
#[param(description = "Operation (+, -, *, /)")]
operation: String,
}
impl Calculator {
async fn execute(&self, _session: Option<SessionContext>) -> McpResult<f64> {
match self.operation.as_str() {
"+" => Ok(self.a + self.b),
"-" => Ok(self.a - self.b),
"*" => Ok(self.a * self.b),
"/" => {
if self.b == 0.0 {
Err("Division by zero".into())
} else {
Ok(self.a / self.b)
}
},
_ => Err("Invalid operation".into()),
}
}
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let server = McpServer::builder()
.name("calculator-server")
.version("1.0.0")
.tool(Calculator { a: 0.0, b: 0.0, operation: "+".to_string() })
.bind_address("127.0.0.1:8642".parse()?) // Different port to avoid conflicts
.build()?;
server.run().await
}
3. Resources with resource_fn()
Create resources that provide data and files using the .resource_fn() method:
use turul_mcp_derive::mcp_resource;
use turul_mcp_server::prelude::*;
use turul_mcp_protocol::resources::ResourceContent;
// Static resource
#[mcp_resource(
uri = "file:///config.json",
name = "config",
description = "Application configuration"
)]
async fn get_config() -> McpResult<Vec<ResourceContent>> {
let config = serde_json::json!({
"app_name": "My Server",
"version": "1.0.0"
});
Ok(vec![ResourceContent::blob(
"file:///config.json",
serde_json::to_string_pretty(&config).unwrap(),
"application/json".to_string()
)])
}
// Template resource with parameter extraction
#[mcp_resource(
uri = "file:///users/{user_id}.json",
name = "user_profile",
description = "User profile data"
)]
async fn get_user_profile(user_id: String) -> McpResult<Vec<ResourceContent>> {
let profile = serde_json::json!({
"user_id": user_id,
"username": format!("user_{}", user_id),
"email": format!("{}@example.com", user_id)
});
Ok(vec![ResourceContent::blob(
format!("file:///users/{}.json", user_id),
serde_json::to_string_pretty(&profile).unwrap(),
"application/json".to_string()
)])
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let server = McpServer::builder()
.name("resource-server")
.version("1.0.0")
.resource_fn(get_config) // Static resource
.resource_fn(get_user_profile) // Template: file:///users/{user_id}.json
.bind_address("127.0.0.1:8643".parse()?) // Different port to avoid conflicts
.build()?;
server.run().await
}
The framework automatically:
- Detects URI templates (
{user_id}patterns) - Extracts template variables from requests
- Maps them to function parameters
- Registers appropriate resource handlers
π Running & Testing the Framework
Quick Start - Verify Everything Works
# 1. Build the framework
cargo build --workspace
# 2. Run compliance tests
cargo test -p turul-mcp-framework-integration-tests --test compliance
# 3. Start a simple server
cargo run -p minimal-server
# 4. Test the server (in another terminal)
curl -X POST http://127.0.0.1:8641/mcp \
-H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","method":"initialize","params":{"protocolVersion":"2025-11-25","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}},"id":1}'
Example Servers - Ready to Run
Core Test Servers:
# Comprehensive server (all MCP features)
cargo run --package comprehensive-server -- --port 8002
# Resource server (17 test resources)
cargo run --package resource-test-server -- --port 8080
# Prompts server (11 test prompts)
cargo run --package prompts-test-server -- --port 8081
Business Application Servers:
# Development team resources
cargo run -p resources-server -- --port 8041
# AI development prompts
cargo run -p prompts-server -- --port 8040
# Real-time notifications
cargo run -p notification-server
# Session management demo
cargo run -p stateful-server
Manual MCP Compliance Verification
Step 1: Initialize Connection
PORT=8080 # Replace with your server's port
curl -X POST http://127.0.0.1:$PORT/mcp \
-H 'Content-Type: application/json' \
-d '{
"jsonrpc": "2.0",
"method": "initialize",
"params": {
"protocolVersion": "2025-11-25",
"capabilities": {},
"clientInfo": {"name": "test", "version": "1.0"}
},
"id": 1
}' | jq
Expected Response:
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"protocolVersion": "2025-11-25",
"serverInfo": {"name": "server-name", "version": "0.3"},
"capabilities": {"tools": {"listChanged": false}}
}
}
Step 2: Test Available Operations
# Get session ID from response and test capabilities
SESSION_ID="your-session-id-here"
# If server has tools capability:
curl -X POST http://127.0.0.1:$PORT/mcp \
-H 'Content-Type: application/json' \
-H "Mcp-Session-Id: $SESSION_ID" \
-d '{"jsonrpc":"2.0","method":"tools/list","params":{},"id":2}' | jq
# If server has resources capability:
curl -X POST http://127.0.0.1:$PORT/mcp \
-H 'Content-Type: application/json' \
-H "Mcp-Session-Id: $SESSION_ID" \
-d '{"jsonrpc":"2.0","method":"resources/list","params":{},"id":3}' | jq
Comprehensive Testing Guide
For detailed testing instructions, server running guides, and compliance verification:
This guide includes:
- β All server running instructions with expected outputs
- β Manual MCP 2025-11-25 compliance verification
- β SSE event stream testing procedures
- β Performance testing and troubleshooting
- β CI/CD integration examples
Quick Compliance Check Script
# Create and run compliance check
cat > quick_check.sh << 'EOF'
#!/bin/bash
PORT=${1:-8080}
echo "π§ͺ Testing MCP server on port $PORT"
INIT_RESPONSE=$(curl -s -X POST http://127.0.0.1:$PORT/mcp \
-H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","method":"initialize","params":{"protocolVersion":"2025-11-25","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}},"id":1}')
if [[ $(echo $INIT_RESPONSE | jq -r '.result.protocolVersion') == "2025-11-25" ]]; then
echo "β
MCP 2025-11-25 compliant"
else
echo "β Not compliant"
exit 1
fi
EOF
chmod +x quick_check.sh
# Test any server
cargo run -p minimal-server &
./quick_check.sh 8641
ποΈ Architecture Overview
Middleware System
The framework provides a trait-based middleware architecture for cross-cutting concerns like authentication, logging, and rate limiting:
use turul_mcp_server::prelude::*;
use std::sync::Arc;
let server = McpServer::builder()
.middleware(Arc::new(AuthMiddleware::new()))
.middleware(Arc::new(LoggingMiddleware))
.middleware(Arc::new(RateLimitMiddleware::new(5, 60)))
.build()?;
Key Features:
- β Transport-agnostic (HTTP, Lambda, etc.)
- β Session-aware (read/write session state)
- β Error short-circuiting with semantic JSON-RPC codes
- β Execution order control (FIFO before, LIFO after dispatch)
Examples:
examples/middleware-logging-server- Request timing and tracing (HTTP)examples/middleware-rate-limit-server- Per-session rate limiting (HTTP)examples/middleware-auth-server- API key authentication (HTTP)examples/middleware-auth-lambda- API key authentication (AWS Lambda)
Testing:
- Test HTTP middleware:
bash scripts/test_middleware_live.sh - Test Lambda middleware:
cargo lambda watch --package middleware-auth-lambda
Documentation:
- ADR 012: Middleware Architecture - Core middleware design
- ADR 013: Lambda Authorizer Integration - API Gateway authorizer support
Lambda Authorizer Integration
Seamless API Gateway authorizer context extraction for Lambda deployments:
// API Gateway authorizer adds context (userId, tenantId, role, etc.)
// β turul-mcp-aws-lambda adapter extracts β injects x-authorizer-* headers
// β Middleware reads headers β stores in session state
// β Tools access via session.get_typed_state("authorizer")
#[async_trait]
impl McpMiddleware for AuthMiddleware {
async fn before_dispatch(
&self,
ctx: &mut RequestContext<'_>,
_session: Option<&dyn SessionView>,
injection: &mut SessionInjection,
) -> Result<(), MiddlewareError> {
// Extract authorizer context from x-authorizer-* headers
let metadata = ctx.metadata();
let mut authorizer_context = HashMap::new();
for (key, value) in metadata.iter() {
if let Some(field_name) = key.strip_prefix("x-authorizer-") {
if let Some(value_str) = value.as_str() {
authorizer_context.insert(field_name.to_string(), value_str.to_string());
}
}
}
if !authorizer_context.is_empty() {
// Store for tools to access
injection.set_state("authorizer", json!(authorizer_context));
}
Ok(())
}
}
Key Features:
- β Supports API Gateway V1 (REST API) and V2 (HTTP API)
- β
Field name sanitization (camelCase β snake_case:
userIdβuser_id) - β Defensive programming (never fails requests)
- β Transport-agnostic (appears as standard HTTP metadata)
- β Session state integration
Example:
examples/middleware-auth-lambda- Full authorizer extraction pattern (V1 nested, V1 flat, V2)- Test events: V1 nested, V1 flat, V2 authorizer shapes (
test-events/)
Core Framework (13 Crates)
turul-mcp-server- High-level server builder with session management and task runtimeturul-mcp-client- Comprehensive client library with HTTP transport supportturul-http-mcp-server- HTTP/SSE transport with CORS and streamingturul-mcp-protocol- Current MCP specification (alias to 2025-11-25)turul-mcp-protocol-2025-11-25- Complete MCP 2025-11-25 specification implementationturul-mcp-protocol-2025-06-18- Legacy MCP specification (backward compatibility)turul-mcp-derive- Procedural macros for all MCP areasturul-mcp-builders- Runtime builder patterns for dynamic MCP componentsturul-mcp-json-rpc-server- Transport-agnostic JSON-RPC 2.0 foundationturul-mcp-session-storage- Session storage backends (SQLite, PostgreSQL, DynamoDB)turul-mcp-task-storage- Task storage for long-running operations (InMemory, with pluggable backends)turul-mcp-aws-lambda- AWS Lambda integration for serverless deploymentturul-mcp-oauth- OAuth 2.1 Resource Server support (JWT validation, Bearer middleware)
Tasks Architecture ADRs
Tasks are an experimental MCP 2025-11-25 capability. The framework provides full implementation support (protocol types, storage, runtime, handlers, and tests). See the architecture decision records for design rationale:
- ADR-015: Protocol Crate Strategy β separate crate for 2025-11-25 spec types including Tasks
- ADR-016: Task Storage Architecture β
TaskStoragetrait, 4 backends, state machine, parity test suite - ADR-017: Task Runtime-Executor Boundary β three-layer split: storage / executor / runtime
- ADR-018: Task Pagination Cursor Contract β deterministic cursor-based pagination across backends
Fine-Grained Trait Architecture
Modern composable design pattern for all MCP areas:
use turul_mcp_builders::prelude::*; // Framework traits + builders
use turul_mcp_protocol::{ToolSchema, ToolResult, schema::JsonSchema, McpResult};
use turul_mcp_server::{McpTool, SessionContext};
use async_trait::async_trait;
use serde_json::Value;
use std::collections::HashMap;
struct MyTool;
// Fine-grained trait composition for maximum flexibility
impl HasBaseMetadata for MyTool {
fn name(&self) -> &str { "my_tool" }
}
impl HasDescription for MyTool {
fn description(&self) -> Option<&str> { Some("Tool description") }
}
impl HasInputSchema for MyTool {
fn input_schema(&self) -> &ToolSchema {
static SCHEMA: std::sync::OnceLock<ToolSchema> = std::sync::OnceLock::new();
SCHEMA.get_or_init(|| {
ToolSchema::object()
.with_properties(HashMap::from([
("input".to_string(), JsonSchema::string())
]))
})
}
}
impl HasIcons for MyTool {} // No icons (default)
impl HasExecution for MyTool {} // No task support (default)
// ToolDefinition automatically implemented via blanket impl
#[async_trait]
impl McpTool for MyTool {
async fn call(&self, _args: Value, _session: Option<SessionContext>)
-> McpResult<CallToolResult> {
Ok(CallToolResult::success(vec![
ToolResult::text("Tool result")
]))
}
}
Supported Areas:
- Tools (
ToolDefinition) - Dynamic tool execution with validation - Resources (
ResourceDefinition) - Static and dynamic content serving - Prompts (
PromptDefinition) - AI interaction template generation - Sampling (
SamplingDefinition) - AI model integration patterns - Completion (
CompletionDefinition) - Context-aware text completion - Logging (
LoggerDefinition) - Dynamic log level management - Roots (
RootDefinition) - Secure file system access boundaries - Elicitation (
ElicitationDefinition) - Structured user input collection - Notifications (
NotificationDefinition) - Real-time event broadcasting
Comprehensive Server Builder
All MCP areas supported with consistent builder pattern:
let server = McpServer::builder()
.name("comprehensive-server")
.version("1.0.0")
.instructions("Full-featured MCP server with all areas")
// Tools
.tool(WeatherTool::new())
.tools(vec![CalculatorTool::new(), ValidationTool::new()])
// Resources
.resource(AppConfigResource::new())
.resources(vec![LogsResource::new(), MetricsResource::new()])
// Prompts
.prompt(CodeReviewPrompt::new())
.prompts(vec![DocumentationPrompt::new(), TestPrompt::new()])
// Sampling
.sampling_provider(CreativeSampling::new())
.sampling_providers(vec![CodeSampling::new(), TechnicalSampling::new()])
// Completion
.completion_provider(IdeCompletion::new())
.completion_providers(vec![SqlCompletion::new(), JsonCompletion::new()])
// Logging
.logger(AuditLogger::new())
.loggers(vec![SecurityLogger::new(), PerformanceLogger::new()])
// Roots
.root_provider(WorkspaceRoot::new())
.root_providers(vec![ConfigRoot::new(), TempRoot::new()])
// Elicitation
.elicitation(OnboardingElicitation::new())
.elicitations(vec![SurveyElicitation::new(), FeedbackElicitation::new()])
// Notifications
.notification_provider(ProgressNotification::new())
.notification_providers(vec![AlertNotification::new(), StatusNotification::new()])
// Server configuration
.bind_address("127.0.0.1:8080".parse()?)
.build()?;
Complete MCP Implementation
All areas implemented with fine-grained trait architecture:
- β
Tools (
ToolDefinition) - Dynamic tool execution with validation, schema generation, and metadata - β
Resources (
ResourceDefinition) - Static and dynamic content serving with access control - β
Prompts (
PromptDefinition) - AI interaction template generation with parameter validation - β
Completion (
CompletionDefinition) - Context-aware text completion with model preferences - β
Logging (
LoggerDefinition) - Dynamic log level management with structured output - β
Notifications (
NotificationDefinition) - Real-time SSE event broadcasting with filtering - β
Roots (
RootDefinition) - Secure file system access boundaries with permissions - β
Sampling (
SamplingDefinition) - AI model integration patterns with constraints - β
Elicitation (
ElicitationDefinition) - Structured user input collection with validation - β Session Management - Stateful operations with UUID v7 correlation IDs
Transport Support
- Streamable HTTP - Production transport via
StreamableHttpHandler(HTTP/1.1 & HTTP/2 with chunked SSE, MCP 2025-11-25) - HTTP+SSE (Legacy) - Backward-compatible transport via
SessionMcpHandler(protocol <= 2024-11-05) - AWS Lambda - Serverless deployment with streaming responses
- Stdio - Planned for future implementation
Note: The framework auto-selects transport handler based on protocol version negotiation.
π Examples Overview
π’ Real-World Business Applications
Development servers for actual business problems:
- comprehensive-server β Development Team Integration Platform
- dynamic-resource-server β Enterprise API Data Gateway
- logging-server β Application Audit & Compliance System
- elicitation-server β Customer Onboarding Platform
- notification-server β Development Team Alert System
- completion-server β IDE Auto-Completion Server
- prompts-server β AI-Assisted Development Prompts
- derive-macro-server β Code Generation & Template Engine
- calculator-add-*-server β Calculator examples (builder, function, derive, manual patterns)
- resources-server β Development Team Resource Hub
π§ Framework Demonstrations
Educational examples showcasing framework patterns:
- Basic Patterns: minimal-server, manual-tools-server, zero-config-getting-started
- Advanced Features: stateful-server, pagination-server, tasks-e2e-inmemory-server
- Macro System: derive-macro-server, function-macro-server, function-resource-server
- Serverless: lambda-mcp-server (AWS Lambda with SQS integration)
- Testing: performance-testing (comprehensive benchmarking suite)
βοΈ Serverless Support
AWS Lambda MCP Server
Full serverless implementation with advanced AWS integration:
cd examples/lambda-mcp-server
# Local development
cargo lambda watch
# Deploy to AWS
cargo lambda build --release
sam deploy --guided
Features:
- π Dual event sources (HTTP + SQS)
- π‘ 200MB streaming responses
- ποΈ DynamoDB session management
- β‘ Sub-200ms cold starts
- π CloudWatch + X-Ray integration
π§ͺ Testing & Quality
π§ͺ Comprehensive Test Coverage - Development Quality
Framework Excellence: 1729+ tests across all components with complete async SessionContext integration:
- β Core Framework Tests - Protocol, server, client, derive macros
- β SessionContext Integration - Full session state management
- β Framework Integration Tests - Proper API usage patterns
- β MCP Compliance Tests - Protocol specification validation
- β Builder Pattern Tests - Runtime tool creation
- β E2E Integration Tests - Streamable HTTP, SSE, task lifecycle
- β Example Applications - Real-world scenario validation
# Run all tests - expect 1729+ passing
cargo test --workspace
# SessionContext integration tests
cargo test -p turul-mcp-framework-integration-tests --test session_context_macro_tests
# Framework integration tests (proper patterns)
cargo test -p turul-mcp-framework-integration-tests --test feature_tests
# MCP compliance tests
cargo test -p turul-mcp-framework-integration-tests --test compliance
π― Framework-Native Testing Patterns
The RIGHT way to test MCP applications - Use framework APIs, not raw JSON:
// β
CORRECT: Framework integration test
use turul_mcp_server::prelude::*;
use turul_mcp_derive::McpTool;
#[derive(McpTool, Default)]
#[tool(name = "calculator", description = "Add numbers")]
struct Calculator {
#[param(description = "First number")] a: f64,
#[param(description = "Second number")] b: f64,
}
impl Calculator {
async fn execute(&self, _session: Option<SessionContext>) -> McpResult<f64> {
Ok(self.a + self.b)
}
}
#[tokio::test]
async fn test_calculator_tool() {
let tool = Calculator { a: 5.0, b: 3.0 };
// Use framework's McpTool trait
let result = tool.call(json!({"a": 5.0, "b": 3.0}), None).await.unwrap();
// Verify using framework result types
assert_eq!(result.content.len(), 1);
match &result.content[0] {
ToolResult::Text { text, .. } => {
let parsed: Value = serde_json::from_str(text).unwrap();
assert_eq!(parsed["output"], 8.0); // Derive macro uses "output"
}
_ => panic!("Expected text result")
}
}
#[tokio::test]
async fn test_server_integration() {
// Use framework builders
let server = McpServer::builder()
.name("test-server")
.tool(Calculator::default())
.build()
.unwrap();
// Server builds successfully with proper type checking
assert!(true);
}
β WRONG: Raw JSON manipulation (old problematic pattern):
// DON'T DO THIS - mixing incompatible JSON-RPC types
let request = json!({
"method": "tools/call",
"params": { "name": "calc" }
});
π SessionContext Integration - Fully Working
Complete session state management with proper test infrastructure:
// SessionContext integration test
use crate::test_helpers::create_test_session;
#[tokio::test]
async fn test_session_state_management() {
let session = create_test_session().await;
// Session state works perfectly
session.set_typed_state("counter", &42i32).await.unwrap();
let value: i32 = session.get_typed_state("counter").await.unwrap();
assert_eq!(value, 42);
// Progress notifications work
session.notify_progress("processing", 50).await;
// Tool execution with session context
let tool = Calculator { a: 1.0, b: 2.0 };
let result = tool.call(json!({"a": 1.0, "b": 2.0}), Some(session)).await.unwrap();
assert_eq!(result.content.len(), 1);
}
Test Infrastructure Available:
TestSessionBuilder- Create real SessionContext instancesTestNotificationBroadcaster- Verify notificationscreate_test_session()- Helper for simple cases- Full storage backend integration
π― Development Patterns
1. Function Macros (Recommended for Simplicity)
Best for: Quick development, natural syntax, minimal boilerplate
use turul_mcp_derive::mcp_tool;
use turul_mcp_server::prelude::*;
#[mcp_tool(name = "weather", description = "Get weather information")]
async fn get_weather(
#[param(description = "City name")] city: String,
#[param(description = "Temperature unit")] unit: Option<String>,
) -> McpResult<String> {
let unit = unit.unwrap_or_else(|| "celsius".to_string());
Ok(format!("Weather in {}: 22Β°{}", city, if unit == "fahrenheit" { "F" } else { "C" }))
}
// Usage in server
let server = McpServer::builder()
.name("weather-server")
.version("1.0.0")
.tool_fn(get_weather)
.build()?;
2. Derive Macros (Struct-Based)
Best for: Complex tools, organized codebases, multiple related functions
use turul_mcp_derive::McpTool;
use turul_mcp_server::prelude::*;
#[derive(McpTool, Clone)]
#[tool(name = "file_manager", description = "File management operations")]
struct FileManager {
#[param(description = "Operation (create, read, delete)")]
operation: String,
#[param(description = "File path")]
path: String,
#[param(description = "File content (for create operation)")]
content: Option<String>,
}
impl FileManager {
async fn execute(&self, session: Option<SessionContext>) -> McpResult<String> {
match self.operation.as_str() {
"create" => {
let content = self.content.as_ref().unwrap_or(&"Empty file".to_string());
Ok(format!("Created file '{}' with content: {}", self.path, content))
},
"read" => Ok(format!("Reading file: {}", self.path)),
"delete" => {
if let Some(session) = session {
session.notify_progress(&format!("Deleting {}", self.path), 100).await;
}
Ok(format!("Deleted file: {}", self.path))
},
_ => Err("Invalid operation".into()),
}
}
}
// Usage in server
let server = McpServer::builder()
.name("file-server")
.version("1.0.0")
.tool(FileManager {
operation: "create".to_string(),
path: "/tmp/example".to_string(),
content: None,
})
.build()?;
3. Builder Pattern (Runtime Flexibility)
Best for: Dynamic tools, configuration-driven systems
use turul_mcp_server::prelude::*;
use serde_json::json;
let multiply_tool = ToolBuilder::new("multiply")
.description("Multiply two numbers")
.number_param("a", "First number")
.number_param("b", "Second number")
.number_output() // Generates {"result": number} schema
.execute(|args| async move {
let a = args.get("a").and_then(|v| v.as_f64())
.ok_or("Missing parameter 'a'")?;
let b = args.get("b").and_then(|v| v.as_f64())
.ok_or("Missing parameter 'b'")?;
Ok(json!({"result": a * b}))
})
.build()
.map_err(|e| format!("Failed to build tool: {}", e))?;
// Usage in server
let server = McpServer::builder()
.name("calculator-server")
.version("1.0.0")
.tool(multiply_tool)
.build()?;
4. Manual Implementation (Maximum Control)
Best for: Performance optimization, custom behavior
use turul_mcp_server::prelude::*; // Re-exports builders prelude + framework traits
use turul_mcp_protocol::{ToolSchema, ToolResult, schema::JsonSchema, McpResult};
use async_trait::async_trait;
use serde_json::Value;
use std::collections::HashMap;
struct ManualTool;
impl HasBaseMetadata for ManualTool {
fn name(&self) -> &str { "manual_tool" }
}
impl HasDescription for ManualTool {
fn description(&self) -> Option<&str> { Some("Manual implementation with full control") }
}
impl HasInputSchema for ManualTool {
fn input_schema(&self) -> &ToolSchema {
static SCHEMA: std::sync::OnceLock<ToolSchema> = std::sync::OnceLock::new();
SCHEMA.get_or_init(|| {
ToolSchema::object()
.with_properties(HashMap::from([
("input".to_string(), JsonSchema::string())
]))
})
}
}
impl HasOutputSchema for ManualTool {
fn output_schema(&self) -> Option<&ToolSchema> { None }
}
impl HasAnnotations for ManualTool {
fn annotations(&self) -> Option<&ToolAnnotations> { None }
}
impl HasToolMeta for ManualTool {
fn tool_meta(&self) -> Option<&HashMap<String, Value>> { None }
}
impl HasIcons for ManualTool {} // No icons
impl HasExecution for ManualTool {} // No task support
#[async_trait]
impl McpTool for ManualTool {
async fn call(&self, _args: Value, _session: Option<SessionContext>)
-> McpResult<CallToolResult> {
// Full control over implementation
Ok(CallToolResult::success(vec![
ToolResult::text("Manual tool with complete control")
]))
}
}
// Usage in server
let server = McpServer::builder()
.name("manual-server")
.version("1.0.0")
.tool(ManualTool)
.build()?;
π§ Client Library
Comprehensive MCP client for HTTP transport:
use turul_mcp_client::{McpClient, McpClientBuilder, transport::HttpTransport};
use std::time::Duration;
// Create HTTP transport
let transport = HttpTransport::new("http://localhost:8080/mcp")?;
// Create client using builder pattern
let client = McpClientBuilder::new()
.with_transport(Box::new(transport))
.build();
// Initialize session
let init_result = client.initialize().await?;
// List available tools
let tools = client.list_tools().await?;
// Call a tool
let result = client.call_tool("add", json!({
"a": 10.0,
"b": 20.0
})).await?;
// List and read resources
let resources = client.list_resources().await?;
let content = client.read_resource("config://app.json").await?;
π Performance Features
Modern Architecture
- UUID v7 - Time-ordered IDs for better database performance and observability
- Workspace Dependencies - Consistent dependency management across 13 core crates and 58 examples
- Rust 2024 Edition - Latest language features and performance improvements
- Tokio/Hyper - High-performance async runtime with HTTP/2 support
Development Quality
- Session Management - Automatic cleanup and state persistence
- Real-time Notifications - SSE-based event streaming
- CORS Support - Browser client compatibility
- Comprehensive Logging - Structured logging with correlation IDs
- Error Handling - Detailed error types with recovery strategies
π MCP Protocol Compliance
Full MCP 2025-11-25 specification support:
- β
JSON-RPC 2.0 - Complete request/response with
_metafields - β Protocol Negotiation - Version compatibility and capability exchange
- β Progress Tracking - Long-running operation support
- β Cursor Pagination - Efficient large dataset navigation
- β Session Isolation - Secure multi-client support
- β Transport Agnostic - Multiple transport implementations
Testing Your Server
# Test tool execution
curl -X POST http://127.0.0.1:8080/mcp \
-H "Content-Type: application/json" \
-H "MCP-Protocol-Version: 2025-11-25" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "add",
"arguments": {"a": 10, "b": 20}
}
}'
# Test SSE notifications (after getting session ID from above request)
curl -N -H "Accept: text/event-stream" \
-H "Mcp-Session-Id: <session-id>" \
http://127.0.0.1:8080/mcp
MCP Session Management Compliance Testing
The framework includes comprehensive compliance testing for MCP session management specification requirements.
Running the Session Management Compliance Test
# 1. Start a server with session storage (choose backend: sqlite, postgres, dynamodb, or inmemory)
cargo run --example client-initialise-server -- --port 52950 --storage-backend dynamodb --create-tables
# 2. In another terminal, run the comprehensive compliance test (IMPORTANT: include RUST_LOG=info)
RUST_LOG=info cargo run --example session-management-compliance-test -- http://127.0.0.1:52950/mcp
# 3. Alternative: Use different storage backends
cargo run --example client-initialise-server -- --port 52951 --storage-backend sqlite --create-tables
RUST_LOG=info cargo run --example session-management-compliance-test -- http://127.0.0.1:52951/mcp
π οΈ Development & Testing
Building the Framework
# Build all workspace crates
cargo build
# Build with release optimizations
cargo build --release
Running Tests
The framework includes 1729+ comprehensive tests covering all functionality. Test server binaries are automatically built when needed - no manual setup required.
# Run all tests (recommended - includes E2E integration tests)
cargo test --workspace
# Run specific test suite
cargo test --package mcp-e2e-shared --test all -- concurrent_session
# Run with logging output
RUST_LOG=info cargo test --workspace
# Clean build and test (verifies auto-build works)
cargo clean && cargo test --workspace
Key Features:
- β Auto-build test servers - Missing test binaries are built automatically on first test run
- β
Zero configuration - Just run
cargo testand everything works - β
Clean workspace support -
cargo clean && cargo testworks without manual steps
The test infrastructure automatically builds required test server binaries (resource-test-server, prompts-test-server, tools-test-server, etc.) when running integration tests. This ensures a seamless developer experience.
What the Compliance Test Verifies
The comprehensive test validates all MCP session management requirements:
- β Session ID Generation: UUID v7 with cryptographic security and ASCII compliance
- β Session Persistence: Proper session validation and storage backend integration
- β Session Expiry: TTL-based cleanup and 404 responses for expired sessions
- β Client Reinitialize: Graceful session recovery on expiry
- β DELETE Termination: Explicit session termination support
- β Session Isolation: Multi-session security and data separation
Expected Output
π§ͺ MCP Session Management Compliance Test
βββββββββββββββββββββββββββββββββββββββββββ
β
Session ID generation compliance verified
β
Session persistence compliance verified
β
Session expiry compliance verified
β
Client reinitialize compliance verified
β
DELETE session termination compliance verified
β
Session isolation compliance verified
π MCP SESSION MANAGEMENT COMPLIANCE: COMPLETE
βββββββββββββββββββββββββββββββββββββββββββββββ
Storage Backend Configuration
DynamoDB (Development):
- 5-minute TTL with automatic cleanup
- GSI indexes for efficient queries
- AWS credentials required
SQLite (Development):
- File-based persistence
- 5-minute TTL with background cleanup
- No external dependencies
PostgreSQL (Enterprise):
- Full SQL features with indexing
- 5-minute TTL with efficient cleanup
- Connection string required
InMemory (Testing):
- Fast, no persistence
- 5-minute TTL with memory cleanup
- Zero configuration
Customizing TTL Configuration
// Custom TTL configuration (default: 5 minutes)
let config = DynamoDbConfig {
session_ttl_minutes: 30, // 30-minute session TTL
event_ttl_minutes: 15, // 15-minute event TTL
..Default::default()
};
Server-Sent Events (SSE) Verification
The framework includes comprehensive SSE testing to verify real-time notification streaming:
Running SSE Tests
# Test SSE functionality in prompts package
cargo test --package mcp-prompts-tests --test all -- sse
# Test specific SSE scenarios
cargo test --package mcp-prompts-tests test_sse_prompts_connection_establishment -- --nocapture
cargo test --package mcp-prompts-tests test_sse_prompts_list_changed_notification -- --nocapture
cargo test --package mcp-prompts-tests test_sse_prompts_session_isolation -- --nocapture
# Test SSE functionality in resources package
cargo test --package mcp-resources-tests --test all -- sse
# Test specific resource SSE scenarios
cargo test --package mcp-resources-tests test_sse_connection_establishment -- --nocapture
cargo test --package mcp-resources-tests test_sse_resource_list_changed_notification -- --nocapture
cargo test --package mcp-resources-tests test_sse_session_isolation -- --nocapture
Expected SSE Test Output
π Starting MCP Resource Test Server on port 18994
β
Session 01997404-d8f4-7b20-b76d-ac1f4be628a3 created and immediately initialized
β
SSE connection: session=01997404-d908-7e62-ae74-af87f1523836, connection=01997404-d909-7001-8b95-296e806aa1e1
β
Total notifications detected: 1
β
Session ID correlation verified
β
Valid SSE format compliance verified
test result: ok. 8 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
Manual SSE Verification
# 1. Start any MCP server with SSE enabled
cargo run --example prompts-server
# 2. Get session ID via initialization
curl -X POST http://127.0.0.1:8080/mcp \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-11-25","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}}}'
# 3. Connect to SSE stream (replace SESSION_ID with actual ID)
curl -N -H "Accept: text/event-stream" \
-H "Mcp-Session-Id: SESSION_ID" \
http://127.0.0.1:8080/mcp
# Expected SSE output:
# id: 0
# event: ping
# data: {"type":"keepalive"}
#
# id: 1
# event: notification
# data: {"type":"resource_update","resource":"prompts/list"}
π Business Value Examples
Enterprise Integration
- dynamic-resource-server: API orchestration across Customer, Inventory, Financial, and HR systems
- logging-server: SOX, PCI DSS, GDPR, and HIPAA compliance reporting
- comprehensive-server: Team collaboration with project management and workflow automation
Developer Productivity
- completion-server: Context-aware IDE completions for multiple languages and frameworks
- prompts-server: AI-powered code review and architecture guidance
- derive-macro-server: Template-based code generation with validation
Customer Experience
- elicitation-server: GDPR-compliant customer onboarding with regulatory forms
- notification-server: Real-time incident management with escalation workflows
π‘οΈ Security & Reliability
- Memory Safety - Rust's ownership system prevents common vulnerabilities
- Type Safety - Compile-time validation with automatic schema generation
- Input Validation - Parameter constraints and sanitization
- Session Isolation - Secure multi-tenant operation
- Audit Logging - Comprehensive activity tracking with UUID v7 correlation
- Resource Limits - Configurable timeouts and memory constraints
π€ Contributing
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Add tests for your changes
- Run the full test suite (
cargo test --workspace) - Benchmark performance impact if applicable
- Commit changes (
git commit -m 'Add amazing feature') - Push to branch (
git push origin feature/amazing-feature) - Open a Pull Request
π License
This project is licensed under the MIT OR Apache-2.0 License - see the LICENSE files for details.
π Acknowledgments
- Model Context Protocol - The foundational specification
- Tokio - Async runtime powering the framework
- Hyper - HTTP foundation with HTTP/2 support
- Serde - Serialization framework
- Rust Community - For exceptional tooling and ecosystem
π Development Status & Current Limitations
π― Current Framework State
- Phase 6 Complete: Session-aware resources implemented with full MCP 2025-11-25 compliance
- 58 Examples Validated: Comprehensive testing campaign completed across all framework areas
- SSE Streaming Verified: Real-time notifications and session-aware logging working correctly
- Beta Status: Active development with API stability considerations before 1.0.0
π§ Current Limitations
Transport & Streaming:
- Lambda SSE: Snapshot-based responses via
handle(), real-time streaming viarun_streaming()/run_streaming_with()with graceful completion-invocation handling - Additional transport variants: Streamable HTTP and legacy HTTP+SSE are supported; stdio remains planned
- CI Environment Testing: SSE tests require port binding capabilities (graceful fallbacks implemented)
Features & Integration:
- Resource Subscriptions:
resources/subscribeMCP spec feature planned for future implementation - Authentication Middleware: OAuth 2.1 Resource Server support via
turul-mcp-oauth(JWT validation, Bearer token middleware,.well-knownmetadata) - Cross-platform Compatibility: Primarily tested on Linux development environments
π Areas for Enhancement
- Performance Monitoring: Basic benchmarks available, comprehensive monitoring planned
- Concurrency Stress Testing: Some resource tests show occasional failures under extreme load
- Browser Compatibility: CORS support available but may need tuning for specific client requirements
Framework Philosophy: We prioritize honest documentation over inflated claims. This beta status reflects our commitment to transparency about the current development state.
π Ready to build MCP servers? Start with our comprehensive examples or check the getting started guide.
π‘ Need help? Open an issue or check our 58 validated examples covering everything from simple calculators to enterprise systems.
