Progress
For long-running tools, Neva can emit progress notifications (notifications/progress) to keep clients informed about how far along a task has progressed.
Enabling Progress Notifications
Progress notifications are emitted via tracing. Configure the notification layer using notification::fmt::layer():
use neva::prelude::*;
use tracing_subscriber::prelude::*;
#[tokio::main]
async fn main() {
tracing_subscriber::registry()
.with(notification::fmt::layer())
.init();
App::new()
.with_options(|opt| opt
.with_tasks(|tasks| tasks.with_all())
.with_default_http())
.run()
.await;
}
with_tasks() enables the Tasks feature, which is required for clients to issue a progressToken alongside a tool call. See the Tasks guide for more details.
Reporting Progress from a Tool
Inject Meta<ProgressToken> into your tool handler to access the progress token provided by the client. Then emit progress events using the tracing::info! macro with the target: "progress" target:
use neva::prelude::*;
#[tool]
async fn long_running_task(token: Meta<ProgressToken>, command: String) {
tracing::info!("Starting {command}");
let mut progress = 0;
loop {
if progress == 100 {
break;
}
tokio::time::sleep(tokio::time::Duration::from_secs(2)).await;
progress += 5;
tracing::info!(
target: "progress",
token = %token, // The progress token from the client
value = progress, // Current progress value
total = 100 // Total (optional)
);
}
tracing::info!("{command} has been successfully completed!");
}
Required tracing fields
| Field | Description |
|---|---|
target: "progress" | Routes the event to the MCP progress notification handler |
token = %token | The ProgressToken from the client request |
value = <number> | Current progress value |
total = <number> | (Optional) Total steps; helps clients display a percentage |
If a client does not include a progressToken in its request, Meta<ProgressToken> will still be present but empty — progress events emitted with it will simply be discarded.
Learn By Example
Here you may find the full example.