use serde_json::json;
use std::collections::HashMap;
use mcp_protocol_sdk::{
client::session::SessionConfig,
client::{ClientSession, McpClient},
core::error::McpResult,
protocol::types::ContentBlock as Content,
transport::http::HttpClientTransport,
};
#[tokio::main]
async fn main() -> McpResult<()> {
#[cfg(feature = "tracing-subscriber")]
tracing_subscriber::fmt::init();
tracing::info!("Starting HTTP MCP client example...");
let client = McpClient::new("http-demo-client".to_string(), "1.0.0".to_string());
let session_config = SessionConfig {
auto_reconnect: true,
max_reconnect_attempts: 3,
reconnect_delay_ms: 2000,
connection_timeout_ms: 10000,
heartbeat_interval_ms: 30000,
..Default::default()
};
let session = ClientSession::with_config(client, session_config);
tracing::info!("Connecting to HTTP server...");
let transport = HttpClientTransport::new(
"http://localhost:3000",
Some("http://localhost:3000/mcp/events"), )
.await?;
match session.connect(transport).await {
Ok(init_result) => {
tracing::info!(
"Connected to HTTP server: {} v{}",
init_result.server_info.name,
init_result.server_info.version
);
tracing::info!("Server capabilities: {:?}", init_result.capabilities);
}
Err(e) => {
tracing::error!("Failed to connect to HTTP server: {}", e);
return Err(e);
}
}
let client = session.client();
match demonstrate_http_operations(&client).await {
Ok(_) => tracing::info!("All HTTP operations completed successfully"),
Err(e) => tracing::error!("HTTP operation failed: {}", e),
}
tracing::info!("Disconnecting from HTTP server...");
session.disconnect().await?;
tracing::info!("HTTP client example completed");
Ok(())
}
async fn demonstrate_http_operations(
client: &std::sync::Arc<tokio::sync::Mutex<McpClient>>,
) -> McpResult<()> {
tracing::info!("=== Listing Tools via HTTP ===");
{
let client_guard = client.lock().await;
let tools_result = client_guard.list_tools(None).await?;
tracing::info!("Available tools via HTTP:");
for tool in &tools_result.tools {
tracing::info!(
" - {}: {}",
tool.name,
tool.description.as_deref().unwrap_or("No description")
);
}
}
tracing::info!("=== Calling HTTP Calculator Tool ===");
{
let client_guard = client.lock().await;
let mut args = HashMap::new();
args.insert("operation".to_string(), json!("multiply"));
args.insert("a".to_string(), json!(25.5));
args.insert("b".to_string(), json!(4.0));
match client_guard
.call_tool("http_calculator".to_string(), Some(args))
.await
{
Ok(result) => {
tracing::info!("HTTP Calculator result:");
for content in &result.content {
match content {
Content::Text { text, .. } => {
tracing::info!(" {}", text);
}
_ => tracing::info!(" (non-text content)"),
}
}
}
Err(e) => tracing::error!("HTTP Calculator tool failed: {}", e),
}
}
tracing::info!("=== Testing Power Operation ===");
{
let client_guard = client.lock().await;
let mut args = HashMap::new();
args.insert("operation".to_string(), json!("power"));
args.insert("a".to_string(), json!(2.0));
args.insert("b".to_string(), json!(8.0));
match client_guard
.call_tool("http_calculator".to_string(), Some(args))
.await
{
Ok(result) => {
tracing::info!("Power operation result:");
for content in &result.content {
match content {
Content::Text { text, .. } => {
tracing::info!(" {}", text);
}
_ => tracing::info!(" (non-text content)"),
}
}
}
Err(e) => tracing::error!("Power operation failed: {}", e),
}
}
tracing::info!("=== Listing HTTP Resources ===");
{
let client_guard = client.lock().await;
let resources_result = client_guard.list_resources(None).await?;
tracing::info!("Available HTTP resources:");
for resource in &resources_result.resources {
tracing::info!(
" - {}: {} ({})",
resource.name,
resource.uri,
resource.mime_type.as_deref().unwrap_or("unknown type")
);
}
}
tracing::info!("=== Reading HTTP Server Status ===");
{
let client_guard = client.lock().await;
match client_guard
.read_resource("http://server/status".to_string())
.await
{
Ok(result) => {
tracing::info!("HTTP Server status:");
for content in &result.contents {
match content {
mcp_protocol_sdk::protocol::types::ResourceContents::Text {
text, ..
} => {
tracing::info!(" {}", text);
}
mcp_protocol_sdk::protocol::types::ResourceContents::Blob { .. } => {
tracing::info!(" (binary content)");
}
}
}
}
Err(e) => tracing::error!("Failed to read HTTP server status: {}", e),
}
}
tracing::info!("=== Reading HTTP Server Metrics ===");
{
let client_guard = client.lock().await;
match client_guard
.read_resource("http://server/metrics".to_string())
.await
{
Ok(result) => {
tracing::info!("HTTP Server metrics:");
for content in &result.contents {
match content {
mcp_protocol_sdk::protocol::types::ResourceContents::Text {
text, ..
} => {
tracing::info!(" {}", text);
}
mcp_protocol_sdk::protocol::types::ResourceContents::Blob { .. } => {
tracing::info!(" (binary content)");
}
}
}
}
Err(e) => tracing::error!("Failed to read HTTP server metrics: {}", e),
}
}
tracing::info!("=== Testing HTTP Ping ===");
{
let client_guard = client.lock().await;
match client_guard.ping().await {
Ok(_) => tracing::info!("HTTP Ping successful"),
Err(e) => tracing::error!("HTTP Ping failed: {}", e),
}
}
Ok(())
}