Snodo.Progress (snodo v0.1.0)

Copy Markdown View Source

Acknowledged progress reporting for an active ordinary MCP request.

Application handlers call report/3 using their request context. A client must have supplied a string/integer progressToken, and the transport must have installed a sink. Otherwise reporting valid values is a harmless no-op.

Only the original request worker may report. Each sink permits one outstanding update, acknowledged only after its transport writes it. Values must increase strictly. The defaults cap each request at 1,000 updates, messages at 4 KiB, and each acknowledgement wait at five seconds. Timeout does not clear the outstanding-update gate, so retrying cannot grow an unbounded mailbox.

The transport owns state/1, handles :mcp_progress synchronous call messages with accept/3, writes their notification, then calls reply/3. It closes the sink after execution, cancellation, disconnect, or a failed write. No process is started by this module, and the synchronous protocol core is unchanged.

Summary

Functions

Admits a synchronous report in the transport owner before writing it.

Binds an installed sink to a validated request context and its current worker.

Marks a sink terminal. Safe to call repeatedly from transport cleanup paths.

Acknowledges a consumed report after writing, releasing its one-outstanding-update gate.

Reports increasing progress, optionally including numeric total and a human-readable message.

Creates an inactive-until-bound sink handle for an existing transport owner.

Initializes counters retained by the transport owning the sink.

Types

report()

@type report() :: %{binding: t(), fields: map()}

result()

@type result() :: :ok | {:error, atom()}

t()

@opaque t()

Functions

accept(state, arg2, arg3)

@spec accept(Snodo.Progress.State.t(), GenServer.from(), report()) ::
  {:ok, map(), Snodo.Progress.State.t()} | {:error, atom()}

Admits a synchronous report in the transport owner before writing it.

from is the original GenServer.from() received with the progress call. The returned state belongs to the transport. Complete the acknowledgement with reply/3 only after the write succeeds or fails.

bind(sink, context)

@spec bind(term(), Snodo.Context.t()) :: t() | nil

Binds an installed sink to a validated request context and its current worker.

close(sink)

@spec close(Snodo.Progress.Sink.t()) :: :ok

Marks a sink terminal. Safe to call repeatedly from transport cleanup paths.

reply(from, arg2, result)

@spec reply(GenServer.from(), report(), result()) :: :ok

Acknowledges a consumed report after writing, releasing its one-outstanding-update gate.

report(context, value, options \\ [])

@spec report(Snodo.Context.t(), number(), keyword()) :: result()

Reports increasing progress, optionally including numeric total and a human-readable message.

sink(owner, options \\ [])

@spec sink(pid(), keyword()) :: Snodo.Progress.Sink.t()

Creates an inactive-until-bound sink handle for an existing transport owner.

state(sink)

Initializes counters retained by the transport owning the sink.