Expand description
MCP notifications/progress plumbing — server-to-client progress
updates emitted from a long-running tool handler.
The MCP spec (2025-11-25) lets a client opt into progress updates by
attaching _meta.progressToken to a request. While the matching tool
is in flight, the server may emit any number of
notifications/progress notifications carrying the same token. The
server must not emit progress for requests without a token, and
progress values must strictly increase per token.
Mechanics mirror the elicitation bus
(crate::mcp_elicit::ElicitationBus): a per-connection ProgressBus
wraps the transport’s outbound JSON sink (installed thread-locally
via install_active_bus), and a per-call ProgressContext is
bound for the duration of a tool handler future via scope_context
(a tokio task-local) so that helpers — notably the
mcp_report_progress stdlib builtin — can find the right token
without taking it as an explicit argument. The split between
thread-local bus and task-local context matters: adapters spawn
concurrent tool calls onto a shared LocalSet, so a thread-local
context would race across awaits.
Spec: https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/progress
Structs§
- Active
BusGuard - RAII guard for
install_active_bus. Connection-scoped, so a thread-local guard is correct here. - Progress
Bus - Per-connection progress notifier.
- Progress
Context - Per-call progress context — the bus plus the token the current
request supplied. Bound for the lifetime of a tool handler future
via
scope_contextso thatmcp_report_progress(...)can find it without explicit threading.
Functions§
- active_
bus - Snapshot the active connection-scoped progress bus, if any.
- current_
context - Snapshot the progress context for the current task, if any.
- install_
active_ bus - Install a connection-scoped
ProgressBusfor the current thread. Connections are single-threaded (the dispatch loop owns one OS thread or LocalSet), so a thread-local is the right scope here: every per-call task derived from this connection sees the same bus. - is_
valid_ progress_ token - MCP progress tokens are constrained to strings or numbers (no nulls, objects, arrays, or booleans). Validate at the boundary so we never echo a malformed token back to the client.
- scope_
context - Run
futurewithctxinstalled as the active progress context. WhenctxisNone, the future runs without a context (socurrent_contextreturnsNonefrom inside it). Use this rather than installing into a thread-local: tool handlers are async and concurrent on the same OS thread, so we need per-task scoping.
Type Aliases§
- Outbound
Fn - Outbound JSON sink for progress notifications.