Proposal: progress reporting (analogue to FastMCP)
Is your feature request related to a problem? Please describe. For long running requests, I understand clients can provide a progress token - this can be used to notify about progress. I'd like to see a convenience method as part of e.g. a tool to provide updates on progress, e.g. for larger up- and downloads.
Describe the solution you'd like In FastMCP there's a way to do this with very convenient DX (see description: https://gofastmcp.com/servers/progress#progress-reporting) - essentially providing the current state and an optional total value in a function and updating it.
Describe alternatives you've considered I've seen there's a notify func but I'm not sure if this covers what I need.
Additional context As stated above, this is about long running requests (e.g. a download or upload of a larger file, processing many items etc.)
Agreed, our progress support is raw.
Please see https://github.com/modelcontextprotocol/go-sdk/pull/462 for a potential improvement. What do you think of that API?
Concrete proposal, implemented in #462. I'm not tied to the name 'Progress', we could call it 'ReportProgress', but I opted for the shorter name.
var ErrNoProgressToken = errors.New("no progress token")
// Progress reports progress on the current request.
//
// An error is returned if sending progress failed. If there was no progress
// token, this error is ErrNoProgressToken.
func (r *ServerRequest[P]) Progress(ctx context.Context, msg string, progress, total float64) error
As an alternative, we could have a concept of a progress reporter that closes over the progress token and session:
func (ServerRequest[P]) Progress() *ProgressReporter
func (*ProgressReporter) Report(context.Context, msg string, progress, total float64) error
This would be more complicated, but has a couple minor advantages: (1) it's easier to pass around the ProgressReporter than the generic ServerRequest, and (2) we could have additional helper methods on the ProgressReporter in the future.
Agreed, our progress support is raw.
Please see #462 for a potential improvement. What do you think of that API?
Nice - many thanks for the very quick response and proposal - this would certainly help implement the use case I described as an example (simple up- or download).
I'm not sure about the arguments though: Should a message msg always be required? Same goes for the total amount - it might be unknown at times.
I'd also vote for keeping the shorter name (Progress).
I'm not sure either of these is the best API.
For a file upload or download, I'd want something like this:
r := NewProgressReporter("downloading " + filename, fileSize) // set message and total; progress is 0
for .... {
n, err := f.Read(buf)
r.Add(n) // increment progress
....
}
And I'd want to send progress reports once every few seconds instead of on every read. (The notifications are ultimately for people, presumably.) So maybe NewProgressReporter takes a duration, and Add only notifies at that interval.
I don't think we have enough data to know what the right API is. I'd like to see more examples in the wild.
@jba I've been thinking about this a bit more as well: for all of these, it's easy to write to write a small wrapper that (more or less) translates to any other API. The one primary value they all add is not having to think about the progress token or Meta.
So we should choose the API that is most useful in the common case. I'd lean toward as just a Progress method on ServerRequest as both simplest and most discoverable.
It's too simple. People will happily call it in an inner loop (e.g. reading a chunk from a file) without realizing they are spamming the client.
Note from the proposal meeting: For now, we think that we will leave this as-is until there is more interest, or an alternative API that doesn't suffer from the backwards-compatibility problems of the one I proposed above.
@jba suggests adding an example for an ergonomic wrapper, to point people in the right direction.
The example should use golang.org/x/time/rate to rate limit the notifications.