A tool call takes a minute. Has it stalled? The agent waits, the user sees nothing, and the developer has to guess whether the server is still working. MCP progress notifications let the server report that work is advancing while the original request stays open.
The mechanism is small: a client attaches a token to a request, and the server can send updates that carry the same token. The final response still arrives through the normal request-response path. Progress is an update, not an answer.
The core idea
The Model Context Protocol lets clients call server features such as tools. For a quick call, a single response is enough. For a long-running export, indexing job, or repository scan, it helps to know how far the server has gotten.
The client opts in by adding _meta.progressToken to the request parameters. The token is a string or integer chosen by the client and must be unique among active requests. While that request is in progress, the server may send notifications/progress messages bearing the token and a numeric progress value. It can also include a total and a human-readable message.
The server might never send an update, even with a token in the request. And an update is not a completion signal.
How progress notifications work
Suppose a client asks an MCP server to scan a repository. A simplified JSON-RPC request could look like this:
{
"jsonrpc": "2.0",
"id": 42,
"method": "tools/call",
"params": {
"name": "scan_repository",
"arguments": { "path": "src" },
"_meta": { "progressToken": "scan-42" }
}
}
The server might report its progress before sending the tool result:
{
"jsonrpc": "2.0",
"method": "notifications/progress",
"params": {
"progressToken": "scan-42",
"progress": 120,
"total": 300,
"message": "Scanned 120 of 300 files"
}
}
The example is illustrative, not a promise that any particular directory server implements repository scanning. The important part is the association: scan-42 ties the notification to the still-active request. The client’s JSON-RPC request ID identifies the eventual response; the progress token identifies interim updates. Do not reuse a token for another request while the first is active.
The protocol requires progress to increase with each notification. total may be omitted when the amount of work is unknown, and both numeric values may be fractional. A server processing an open-ended operation could report a growing count of records handled without claiming a percentage. If the client receives a total, it can show a progress bar; without one, it can show an activity indicator and the message.
When the operation ends, the server sends its normal response and stops sending progress notifications. A client should clear its progress state then, including when the request ends in an error. Do not treat a notification showing progress equal to total as the final tool result. The response is the completion signal for the request.
Why this matters for AI agents
A useful agent interface needs to distinguish “still working” from “done.” If an agent calls a slow MCP tool and the server stays silent, the client has little to show the user besides a spinner. Progress messages can expose a real status such as “Scanning files” or “Processed 120 records” without returning a partial result as if it were complete.
That distinction also helps orchestration. A client handling multiple in-flight requests can use each token to display the right status beside the right task. The token is correlation metadata, not an authorization mechanism or a substitute for checking whether the user was allowed to start the operation.
What progress cannot do: cancel a job, extend an HTTP timeout by itself, or guarantee the client will render updates. It only reports on an active request. If a job needs to outlive that request, design an explicit job resource or polling workflow instead of keeping the request open indefinitely. To stop work, use the protocol’s cancellation mechanism where supported and handle cleanup separately.
Practical design choices
Report meaningful milestones rather than every item in a loop. A server that emits a notification for every file in a large repository can flood the connection and the interface. The MCP progress specification recommends rate limiting on both sides.
Choose units that readers can understand. If progress means processed records, let total mean total records. If a job has several phases with different units, a short message can explain the phase, but avoid making a percentage jump backward when switching phases. The numeric progress must keep increasing across notifications for the request.
On the client side, keep the original request pending and route updates by token. Make the UI resilient to a server that sends no updates at all: progress reporting is optional even when the client asks for it. On the server side, never emit notifications for an unknown or completed token. A stale notification can make a finished operation appear active again.
This is separate from MCP logging. Logs help inspect events and diagnose behavior; progress messages describe the state of a particular in-flight request. A server might implement both, but clients should not make users sift through logs to find out whether a tool call is moving.
FAQ
Q: Are progress notifications required for every MCP tool call?
A: No. They are optional and most useful for long-running requests. The client requests updates with a progress token, but the server can still finish without sending any notifications.
Q: Is progress always a percentage?
A: No. It is a numeric value that increases. When a total is present, the client can calculate a proportion. Without a total, it can show a count or a general activity state.
Q: Can a progress notification contain the final tool output?
A: It is not the final response. Keep result data in the response to the original request; use progress notifications for status while that request is still running.
Q: Can the same progress token be used for two simultaneous requests?
A: No. Tokens must be unique across active requests so the client can associate updates with the correct operation.