use async_trait::async_trait;
use pmcp::{
types::{
capabilities::{ClientCapabilities, ServerCapabilities},
protocol::LogLevel,
},
Client, Server, StdioTransport, ToolHandler,
};
use serde_json::{json, Value};
use tokio::time::{sleep, Duration};
#[allow(dead_code)]
struct LoggingTool;
#[async_trait]
impl ToolHandler for LoggingTool {
async fn handle(
&self,
_arguments: Value,
_extra: pmcp::RequestHandlerExtra,
) -> pmcp::Result<Value> {
pmcp::log(LogLevel::Debug, "Starting tool execution", None).await;
for i in 1..=3 {
pmcp::log(
LogLevel::Info,
&format!("Processing step {}/3", i),
Some(json!({
"step": i,
"total": 3,
"progress": format!("{}%", i * 33)
})),
)
.await;
sleep(Duration::from_millis(500)).await;
}
pmcp::log(
LogLevel::Warning,
"Resource usage is high",
Some(json!({
"cpu": "85%",
"memory": "92%",
"action": "consider scaling"
})),
)
.await;
pmcp::log(LogLevel::Info, "Tool execution completed", None).await;
Ok(json!({
"status": "completed",
"steps_processed": 3
}))
}
}
#[allow(dead_code)]
async fn run_logging_server() -> Result<(), Box<dyn std::error::Error>> {
println!("🖥️ Starting logging server...\n");
let server = Server::builder()
.name("logging-server")
.version("1.0.0")
.capabilities(ServerCapabilities::tools_only())
.tool("process_with_logs", LoggingTool)
.build()?;
pmcp::log(
LogLevel::Info,
"Server initialized and ready",
Some(json!({
"name": "logging-server",
"version": "1.0.0",
"pid": std::process::id()
})),
)
.await;
server.run_stdio().await?;
Ok(())
}
async fn run_logging_client() -> Result<(), Box<dyn std::error::Error>> {
println!("💻 Starting logging client...\n");
let transport = StdioTransport::new();
let mut client = Client::new(transport);
let capabilities = ClientCapabilities::minimal();
println!("Connecting to server...");
let _server_info = client.initialize(capabilities).await?;
println!("✅ Connected!\n");
println!("📞 Calling tool that generates logs:\n");
let result = client
.call_tool("process_with_logs".to_string(), json!({}))
.await?;
println!(
"\n✅ Tool result: {}",
serde_json::to_string_pretty(&result.content)?
);
println!("\n📝 Client-side logging examples:\n");
println!(" [DEBUG] Debugging connection state");
println!(" [INFO] Processing completed | {{\"items_processed\":42,\"duration_ms\":1337}}");
println!(" [WARNING] Cache miss rate high | {{\"miss_rate\":\"45%\",\"threshold\":\"20%\"}}");
Ok(())
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
tracing_subscriber::fmt()
.with_env_filter("pmcp=info")
.init();
println!("=== MCP Logging Example ===");
println!("This example demonstrates logging in both server and client.\n");
run_logging_client().await?;
println!("\n📌 Note: To see server-side logging, run the server example separately.");
Ok(())
}