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

# pull_inbox

> Drain the calling agent's inbox one page at a time against a server-owned acknowledgement cursor, over MCP.

Drain this agent's inbox one page at a time against a **server-owned** acknowledgement cursor. The server remembers how far you have acknowledged, so your client does not have to persist a watermark anywhere.

Dispatches to the `pull_inbox` internal service method — the same one behind `POST /v1/inbox:pull` and the gRPC `PullInbox`.

## Parameters

Every parameter is optional. `{}` is the normal steady-state call: *drain from my stored cursor, at the server's page cap, acknowledging nothing.*

| Name    | Type    | Required | Default              | Description                                                                                                                                                                                                                 |
| ------- | ------- | -------- | -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `since` | integer | No       | your stored cursor   | Explicit page floor: return deliveries with `delivery_seq > since`, overriding your stored cursor. This is the re-read escape hatch — pass a lower value to see acknowledged deliveries again.                              |
| `ack`   | integer | No       | nothing acknowledged | Acknowledge up to this `delivery_seq` — normally the previous response's `window_high`. Monotonic (a lower value never rewinds), clamped to the window this call examined, and applied **before** this call's page is read. |
| `limit` | integer | No       | the server's cap     | Requested page size, clamped down to the server's `pull.max_batch` (never up). Size it to your context-injection budget.                                                                                                    |

There is deliberately no agent-id parameter. Over MCP your identity is the launch token authenticated once at startup, so the inbox you drain is always your own.

## Returns

```json theme={null}
{
  "items": [
    { "delivery_seq": 41, "diff": { /* MemoryDiff */ }, "delivery": { /* DeliveryRecord */ } }
  ],
  "cursor": 38,
  "window_high": 42,
  "has_more": true
}
```

Returned as the `structuredContent` payload. Four fields answering four different questions:

| Field         | What it answers                                                                                                                                                                                      |
| ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `items`       | What may I see? Each item carries its `delivery_seq`, the delivered memory diff, and its delivery record. The page is presented score-first for display; the sequences remain the cursor's business. |
| `cursor`      | What is my acknowledged watermark *after* this call? Lets you detect an `ack` that was clamped or ignored.                                                                                           |
| `window_high` | How far may I acknowledge next? The top of the delivery window this call examined.                                                                                                                   |
| `has_more`    | Is there more waiting right now?                                                                                                                                                                     |

<Warning>
  `window_high` is **not** the newest `delivery_seq` in `items`, and `has_more` is **not** `items.length == limit`. A delivery your read scope filters out still counts toward the window, so `window_high` can sit strictly above every item you received — and acknowledging your newest *item* instead would pin the cursor below that row and re-scan it on every pull, forever. Likewise a narrow scope can filter a full window down to an empty page, so `has_more: true` may legitimately arrive with no items at all. Send `window_high` back as `ack`; do not derive either value from `items`.
</Warning>

## The drain loop

Pull and acknowledge ride **one** round trip. The `ack` you send is applied before that same call's page is read, so a steady-state client sends only the previous `window_high` and receives fresh items back:

```json theme={null}
{"name": "pull_inbox", "arguments": {}}
{"name": "pull_inbox", "arguments": {"ack": 42}}
{"name": "pull_inbox", "arguments": {"ack": 57}}
```

This matters because the drain typically runs on an agent's pre-turn hook, inside a single-digit-second budget. A design needing two calls per page would halve the achievable drain rate.

If you handled only part of a page — the normal case under an injection cap — acknowledge the largest sequence *all* of whose items you handled, not the newest one you received. Because the page is presented score-first, those are generally not the same item. Whatever you send is clamped to `window_high`, so a runaway `ack` cannot bury your future inbox.

## Example

Request:

```json theme={null}
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "pull_inbox",
    "arguments": { "ack": 42, "limit": 8 }
  }
}
```

Response:

```json theme={null}
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "content": [
      { "type": "text", "text": "{\"items\":[],\"cursor\":42,\"window_high\":42,\"has_more\":false}" }
    ],
    "structuredContent": { "items": [], "cursor": 42, "window_high": 42, "has_more": false },
    "isError": false
  }
}
```

## Annotations

The tool's MCP behaviour hints, as emitted in `tools/list` (advisory display metadata — see [the annotations contract](/mcp/overview#tool-annotations)):

| `readOnlyHint` | `destructiveHint` | `idempotentHint` | `openWorldHint` |
| -------------- | ----------------- | ---------------- | --------------- |
| `false`        | `false`           | `false`          | `false`         |

The only tool whose hints differ from [`inbox`](/mcp/tools/inbox), and deliberately so:

* **Not read-only.** A call carrying `ack` writes your acknowledgement cursor. The hint is one static value per tool and cannot say "read-only unless you pass `ack`", so it declares the honest `false`.
* **Not destructive.** The write is a monotonic advance on a retained row. Nothing is deleted or cleared, and the acknowledged deliveries themselves remain readable by passing a lower `since`.
* **Not idempotent.** The ack clamp is recomputed from your *current* cursor, so an identical repeated call can advance it again.

## Choosing between `pull_inbox` and `inbox`

Both drain your own inbox and neither leaks another agent's deliveries. They differ in who owns the position:

|              | [`inbox`](/mcp/tools/inbox)                | `pull_inbox`                                 |
| ------------ | ------------------------------------------ | -------------------------------------------- |
| Cursor owner | your client, via `last_seen`               | the server, via an acknowledgement cursor    |
| Cursor unit  | an RFC3339 timestamp                       | a delivery sequence                          |
| Paging       | none — the whole history since `last_seen` | a page envelope with an explicit ack ceiling |
| Repeat call  | replays the same items                     | advances past what you acknowledged          |

Reach for `pull_inbox` when your client cannot durably store a watermark of its own — which covers most agent harnesses, whose session abstractions persist conversation items and nothing else. Reach for `inbox` when you genuinely want a time-bounded replay you control.

## Related

* [place\_beacon](/mcp/tools/place-beacon) to attract diffs into your inbox.
* [inbox](/mcp/tools/inbox) for the client-watermarked drain.
* [Gossip propagation](/concepts/gossip-propagation) for how diffs reach you.
