> ## Documentation Index
> Fetch the complete documentation index at: https://docs.getmcp.com/llms.txt
> Use this file to discover all available pages before exploring further.

# notifications/progress

> Server-emitted progress updates for long-running tool calls.

`notifications/progress` is a **server → client** notification. The client opts in by sending `_meta.progressToken` on the `tools/call` params; the server can then emit progress events as the work proceeds.

GetMCP exposes an emitter API that custom tools and integrations can call. The built-in `ToolExecutor` is synchronous and doesn't auto-emit progress — it's straightforward request-response — so this is wired for tools you author yourself.

***

## Opt-in From the Client

The client signals it wants progress updates by attaching a `progressToken` to its `tools/call` request:

```json theme={null}
{
  "jsonrpc": "2.0",
  "id":      7,
  "method":  "tools/call",
  "params": {
    "name":      "long_running_export",
    "arguments": { "table": "orders" },
    "_meta": { "progressToken": "export-abc123" }
  }
}
```

GetMCP captures the token and stores it on the request context. If the token is missing, the emitter is a no-op and zero traffic is generated.

***

## Wire-level Shape (emitted by server)

```json theme={null}
{
  "jsonrpc": "2.0",
  "method":  "notifications/progress",
  "params": {
    "progressToken": "export-abc123",
    "progress":      42,
    "total":         100,
    "message":       "Processing batch 42 of 100"
  }
}
```

<ParamField body="params.progressToken" type="string | integer" required>
  Echoes the token the client supplied on the originating request.
</ParamField>

<ParamField body="params.progress" type="number" required>
  Monotonically increasing counter. Same units as `total` when set.
</ParamField>

<ParamField body="params.total" type="number">
  Optional ceiling — clients render a percentage when both are present.
</ParamField>

<ParamField body="params.message" type="string">
  Optional human-readable status line ("Processed 42 of 100 orders").
</ParamField>

***

## Emitting From PHP

```php theme={null}
use GetMCP\Protocol\ProgressEmitter;

ProgressEmitter::emit(
    $session_id,
    $progress_token,   // captured from the request context
    42,                // progress
    100,               // total (optional)
    'Processing batch 42 of 100' // message (optional)
);
```

The emitter pushes the notification onto the per-session outbound queue. The next HTTP response from this session will include the notification as part of a JSON-RPC batch.

A typical pattern inside a custom tool's loop:

```php theme={null}
foreach ( $batches as $i => $batch ) {
    process_batch( $batch );
    ProgressEmitter::emit( $session_id, $token, $i + 1, count( $batches ) );
}
```

***

## Delivery Model

Because Streamable HTTP doesn't keep an SSE channel open by default, progress notifications are **queued** server-side and **delivered piggy-backed onto the next response**. For long-running tool calls this means:

* If the tool runs in a single HTTP request that takes 30 seconds, progress is queued but not delivered until the request completes — at which point all progress events arrive as a batch alongside the final result.
* If the tool returns quickly and the client polls again, progress emitted between calls arrives on the next response.

The emitter API is forward-compatible: a future SSE GET handler can drain the same queue without any change to the emit call sites.

***

<Note>
  Progress notifications are *informational*. Clients are not required to render them. Always make sure your tool returns a final result regardless of whether progress was delivered — the protocol guarantees the result, not the progress events.
</Note>
