Progress
The MCP Ruby SDK supports progress tracking for long-running tool operations, following the MCP Progress specification.
How Progress Works
- Client Request: The client sends a
progressTokenin the_metafield when calling a tool - Server Notification: The server sends
notifications/progressmessages back to the client during tool execution - Tool Integration: Tools call
server_context.report_progressto report incremental progress
Reporting Progress from Tools
Tools that accept a server_context: parameter can call report_progress on it. The server automatically wraps the context in an MCP::ServerContext instance that provides this method:
class LongRunningTool < MCP::Tool
description "A tool that reports progress during execution"
input_schema(
properties: {
count: { type: "integer" },
},
required: ["count"]
)
def self.call(count:, server_context:)
count.times do |i|
# Do work here.
server_context.report_progress(i + 1, total: count, message: "Processing item #{i + 1}")
end
MCP::Tool::Response.new([{ type: "text", text: "Done" }])
end
end
The server_context.report_progress method accepts:
progress(required) - current progress value (numeric)total:(optional) - total expected value, so clients can display a percentagemessage:(optional) - human-readable status message
report_progress is a no-op when the request carried no progressToken, and both numeric and string tokens are supported.
On the modern lifecycle, progress notifications emitted during a request ride the request’s own SSE response stream. The bundled transport buffers them and flushes after the handler returns, so they preserve order but arrive together with the final response rather than in real time.
Client Side
Requesting progress is the client’s side of the contract: pass progress_token: to MCP::Client#call_tool and the token is sent as _meta.progressToken, as shown on the client Transports page. The bundled client transports do not currently expose a callback for observing the incoming notifications/progress messages; the token’s effect is visible on the server side only.