Skip to main content

Logging

Neva integrates with Rust's tracing ecosystem to emit structured log messages. When configured correctly, these log messages are automatically forwarded to connected clients as MCP log notifications (notifications/message).

Setup

To enable MCP log notifications, configure tracing_subscriber with Neva's NotificationFormatter and register the handle with with_logging():

use neva::prelude::*;
use tracing_subscriber::{filter, reload, prelude::*};

#[tokio::main]
async fn main() {
// Create a reloadable log filter with an initial level
let (filter, handle) = reload::Layer::new(filter::LevelFilter::DEBUG);

tracing_subscriber::registry()
.with(filter)
.with(tracing_subscriber::fmt::layer()
.event_format(notification::NotificationFormatter)) // Route logs to MCP clients
.init();

App::new()
.with_options(|opt| opt
.with_stdio()
.with_logging(handle)) // Register the reload handle
.run()
.await;
}

The reload::Layer allows the MCP server to dynamically change the log level at runtime, which MCP clients can request via the logging/setLevel method.

Emitting Log Messages from Tools

Once logging is configured, use standard tracing macros inside your handlers to emit log messages:

#[tool]
async fn my_tool() {
tracing::info!(logger = "my_tool", "Processing started");
tracing::warn!(logger = "my_tool", "Something looks off");
tracing::debug!(logger = "my_tool", "Debug details here");
}

The optional logger field is forwarded to the client as part of the notification payload, allowing clients to identify the source of each log entry.

Log Levels

Neva maps tracing severity levels to MCP log levels as follows:

tracing levelMCP log level
ERRORerror
WARNwarning
INFOinfo
DEBUGdebug
TRACEdebug

Progress Notifications via Tracing

For long-running tools, Neva also uses tracing to emit progress notifications (notifications/progress). See the Progress guide for details.

Learn By Example

Here you may find the full example.