A tool call of an MCP server can take long, such as a call that works on
many hosts. When the call came with a progress token, the client can show
how far it got. mcpprogress.Notifier is a sink that
sends the progress notifications of the Model Context Protocol.
Procedure#
- When a call comes with a progress token, make a Bus for that call alone, with a Notifier among its sinks.
- Give the Notifier a
Sendthat puts the token in the notification and sends it on the call’s session. The kit imports no MCP SDK (decision 3). - Run the call under the Bus.
- When the handler returned, close the Bus, then close the Notifier with a short deadline. Then answer the call. So nothing is sent after the result.
var last string
n := mcpprogress.New(mcpprogress.Options{
Send: func(_ context.Context, progress, total float64, message string) error {
last = fmt.Sprintf("%v/%v %s", progress, total, message)
return nil
},
})
bus := progress.NewBus(progress.BusOptions{Sinks: []progress.Sink{n}, Program: "prog"})
ctx := progress.WithBus(context.Background(), bus)
fanout.Map(ctx, []string{"exe1", "exe2", "exe3"}, fanout.MapOptions[string]{Step: "probe the nodes"},
func(context.Context, string) (struct{}, error) { return struct{}{}, nil })
bus.Close()
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
if err := n.Close(ctx); err != nil {
fmt.Println(err)
}
fmt.Println(last)3/3 probe the nodes: 3/3 doneprogress/mcpprogress/example_test.go. CI runs it and checks its output.What the client sees#
- The progress counts the targets that ended, of how many the call expects. It never goes back, and never passes the total.
- A notification goes out at most once per interval, and at once when a step or a batch ends. It goes only when more targets ended.
- The message is a line such as
read the groups: 3/16 done, 1 failed.
The rate, the rule that the progress only grows, and the words of the line are an interface (decisions 27 and 32).
NOTE
To forward the progress of a child that runs the call, poll its event log into a Forwarder with the Notifier as its sink. See Follow a child process.