- Progress notifications require a request-scoped progressToken from the client.
- Clients may omit progress support or choose not to render notifications.
- Rate-limit meaningful milestones and stop updates after completion or cancellation.
- Tasks provide durable state when progress notifications are not enough for long-running work.
MCP progress notifications are optional, request-scoped updates for long-running work. A client that wants updates includes a progressToken in the request metadata. The receiving side may then send notifications/progress with that token, a progress value, an optional total, and an optional human-readable message. The token connects an update to the request that is still in progress.
This article is verified against the MCP 2025-11-25 progress specification and current SDK and client documentation on September 12, 2026. Support is not uniform across hosts. A successful implementation in MCP Inspector does not prove that another host will request or display progress.
The progress flow
{
"jsonrpc": "2.0",
"id": 7,
"method": "tools/call",
"params": {
"name": "build_report",
"arguments": { "project": "acme" },
"_meta": { "progressToken": "request-7-progress" }
}
}The server may send updates during the operation. Each update repeats the same progressToken. The progress value should increase as work advances. total is optional because the server may not know the total amount of work in advance.
{
"jsonrpc": "2.0",
"method": "notifications/progress",
"params": {
"progressToken": "request-7-progress",
"progress": 4,
"total": 10,
"message": "Collected four data sources"
}
}What progressToken does and does not mean
- It correlates a progress update with an active request.
- It is not a public job ID, a durable task handle, or proof that the user saw an update.
- It must be unique among active requests from the sender.
- It can be a string or an integer, but the receiver should treat it as a correlation value rather than an encoded instruction.
- A receiver may choose not to send progress even when a token was provided.
Why progress does not appear
The most common explanation is that the client did not request progress. The protocol makes the token opt-in. Another explanation is that the client requested it but does not expose or render notifications/progress in its user interface. A third is that a transport or SDK buffered the messages until the final result, or that the server sent updates after the request had already completed.
- Log whether the incoming request contained progressToken before starting work.
- Log the token only in a controlled, non-sensitive form and never confuse it with an authorization credential.
- Send updates from the same request context and stop after completion or cancellation.
- Check the host's documentation or a reproducible client test instead of inferring support from its MCP branding.
- Test with a small deterministic tool before debugging a large external workflow.
Progress values and rate limits
Progress is not a log stream. Sending one notification for every row, network retry, or internal function call can flood a client and add work to the same connection that carries the result. Choose meaningful milestones, coalesce frequent updates, and apply a time or count based rate limit.
The progress number should increase even when total is unknown. It can represent completed stages, processed records, or an estimated unit of work, but the meaning should be stable within one operation. Do not reset progress to zero when moving between internal phases unless the application clearly defines a different nested progress model.
Progress versus task polling
Progress notifications are a best-effort view of an active request. Tasks are a durable asynchronous protocol extension for operations that may outlive the original request or connection. A task can be polled with tasks/get and can expose a final result or error. Progress can supplement a task, but it is not a replacement for durable state.
Progress versus cancellation
A progress update tells the receiver how work is advancing. It does not request that work stop. Cancellation has its own semantics, and in the 2025-era protocol the sender can use notifications/cancelled for an in-progress request. A server should connect cancellation to an AbortSignal or equivalent cleanup path and continue to handle the race where cancellation arrives after work has completed.
A safe server pattern
async function buildReport(ctx: { progressToken?: string }) {
const steps = ["load", "query", "format", "save"];
for (let index = 0; index < steps.length; index += 1) {
await runStep(steps[index]);
if (ctx.progressToken !== undefined) {
await sendProgress({
progressToken: ctx.progressToken,
progress: index + 1,
total: steps.length,
message: "Completed a report stage",
});
}
}
return { ok: true };
}The example makes progress conditional on the request context. In a real SDK, use its request metadata and notification API rather than inventing a parallel wire format. Keep the progress path non-blocking where possible, because telemetry or UI updates should not turn into a new failure point for the tool itself.
Testing matrix
- No progressToken: the tool completes without sending notifications.
- One token: updates correlate to the correct request.
- Two concurrent tokens: updates never cross between requests.
- Unknown token: the server does not emit an unrelated notification.
- Non-increasing progress: the server or client reports a validation failure in a test fixture.
- Slow client: updates are bounded and the final result remains deliverable.
- Cancellation race: work cleans up whether cancellation arrives before or after the final result.
- Client that ignores notifications: the user still receives an honest final state or task handle.
What TrackMCP can and cannot tell you
TrackMCP can correlate observed tool duration, server-side errors, explicit workflow outcomes, and any bounded progress-related event that the instrumented server chooses to emit. This helps answer whether the server spent time in a slow operation and whether it eventually returned a result.
TrackMCP cannot tell you that a progress notification was displayed, that a host updated its UI, or that a model used the message to decide what to do next. Those are client and host behaviors outside the server boundary.
Does every MCP client support progress notifications?
No. Progress is optional, and support varies by client. A client may omit progressToken or may not render notifications even when the server sends them.
What should a server do when progressToken is missing?
Continue without progress notifications and use a final result, a durable task extension, or an application-specific status flow when the operation needs a longer-lived status channel.
Is progress the same as a task?
No. Progress is request-scoped and best effort. A task is durable asynchronous state that a client can poll and retrieve after the original request or connection is gone.
About the publisher
TrackMCP, also written Track MCP
TrackMCP helps teams understand which clients connect to their MCP servers, which tools agents use, and where workflows fail. Learn more about Track MCP.
See this on your own server
TrackMCP turns your MCP server's calls into adoption, workflows, and outcomes. One line to install.