#[cfg(feature = "transport-sse")]
#[path = "common/mod.rs"]
mod common;
#[cfg(feature = "transport-sse")]
mod sse_example {
#![allow(deprecated)]
use actix_web::{App, HttpResponse, HttpServer, Result, middleware, web};
use rmcp_actix_web::transport::SseService;
use std::{sync::Arc, time::Duration};
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
use super::common::calculator::Calculator;
async fn health_check() -> Result<HttpResponse> {
Ok(HttpResponse::Ok().json(serde_json::json!({
"status": "healthy",
"service": "mcp-calculator",
"version": "1.0.0"
})))
}
async fn root() -> Result<HttpResponse> {
Ok(HttpResponse::Ok().json(serde_json::json!({
"message": "MCP Calculator Service",
"endpoints": {
"health": "/health",
"mcp_sse": "/api/v1/mcp/sse",
"mcp_post": "/api/v1/mcp/message"
},
"documentation": "https://modelcontextprotocol.io/"
})))
}
pub async fn run() -> Result<(), Box<dyn std::error::Error>> {
tracing_subscriber::registry()
.with(
tracing_subscriber::EnvFilter::try_from_default_env()
.unwrap_or_else(|_| "info".to_string().into()),
)
.with(tracing_subscriber::fmt::layer())
.init();
let bind_addr = "127.0.0.1:8080";
tracing::info!("Starting SSE composition example server on {}", bind_addr);
let sse_service = SseService::builder()
.service_factory(Arc::new(|| Ok(Calculator::new()))) .sse_path("/sse".to_string()) .post_path("/message".to_string()) .sse_keep_alive(Duration::from_secs(30)) .build();
let server = HttpServer::new(move || {
App::new()
.wrap(middleware::Logger::default())
.wrap(middleware::NormalizePath::trim())
.route("/", web::get().to(root))
.route("/health", web::get().to(health_check))
.service(
web::scope("/api").service(
web::scope("/v1")
.service(web::scope("/mcp").service(sse_service.clone().scope())),
),
)
})
.bind(bind_addr)?
.run();
tracing::info!("🚀 Server started successfully!");
tracing::info!("📊 Health check: http://{}/health", bind_addr);
tracing::info!("🔌 MCP SSE endpoint: http://{}/api/v1/mcp/sse", bind_addr);
tracing::info!(
"📨 MCP POST endpoint: http://{}/api/v1/mcp/message",
bind_addr
);
tracing::info!("Press Ctrl+C to stop the server");
tokio::select! {
result = server => {
if let Err(e) = result {
tracing::error!("HTTP server error: {}", e);
}
}
_ = tokio::signal::ctrl_c() => {
tracing::info!("Received Ctrl+C, shutting down gracefully");
}
}
Ok(())
}
}
#[cfg(feature = "transport-sse")]
#[actix_web::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
sse_example::run().await
}
#[cfg(not(feature = "transport-sse"))]
fn main() {
eprintln!("This example requires the 'transport-sse' feature to be enabled.");
eprintln!("Run with: cargo run --example composition_sse_example --features transport-sse");
std::process::exit(1);
}