> ## Documentation Index
> Fetch the complete documentation index at: https://ngquct-docs-fix-500-query-results.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# MCP Subscriptions

> subscriptions/listen, the notification filter TablePro honors, and what it deliberately does not send

Hold one POST open and TablePro streams every notification you asked for down it until you hang up. `subscriptions/listen` replaces `resources/subscribe` and the old `GET` stream, and it is modern-era only: a legacy client gets `-32601`.

## Opening a subscription

```json theme={null}
{
  "jsonrpc": "2.0",
  "id": "sub-1",
  "method": "subscriptions/listen",
  "params": {
    "notifications": {
      "resourcesListChanged": true,
      "resourceSubscriptions": ["tablepro://connections/9f1f0c3e-2e3d-4b14-9c3a-1d2f4ad1f6f1/schema"]
    },
    "_meta": {
      "io.modelcontextprotocol/protocolVersion": "2026-07-28",
      "io.modelcontextprotocol/clientCapabilities": {}
    }
  }
}
```

`params.notifications` is required and must be an object. Send `Mcp-Method: subscriptions/listen` like any other request.

The request id is the subscription id, so it must not be null. Every notification on this stream carries it in `_meta.io.modelcontextprotocol/subscriptionId`, which is how a client with several subscriptions open tells them apart.

## The acknowledgment

Before anything else, the server answers with what it will actually send:

```json theme={null}
{
  "jsonrpc": "2.0",
  "method": "notifications/subscriptions/acknowledged",
  "params": {
    "notifications": { "resourcesListChanged": true, "resourceSubscriptions": ["tablepro://connections/9f1f.../schema"] },
    "_meta": { "io.modelcontextprotocol/subscriptionId": "sub-1" }
  }
}
```

Compare it against what you asked for. Anything missing will never arrive.

## What TablePro honors

| Filter field            | Honored | Notes                                                                              |
| ----------------------- | :-----: | ---------------------------------------------------------------------------------- |
| `resourcesListChanged`  |   yes   | Fires when the set of connected connections this token can see changes.            |
| `resourceSubscriptions` |   yes   | Only `tablepro://connections/{id}/schema` URIs.                                    |
| `toolsListChanged`      |    no   | Both lists are fixed, and `server/discover` reports `listChanged: false` for each. |
| `promptsListChanged`    |    no   | Same.                                                                              |

Every URI in `resourceSubscriptions` is checked twice. It has to parse as a connection schema URI, and its connection has to be inside the token's allowlist. Anything else is dropped silently, so the acknowledgment is the only place you find out. A token without `resources:read` gets an empty filter back, whatever it asked for.

The URI you get back is canonical, so one that differs only in case or percent-encoding comes back normalized.

## Reading the stream

The response switches to `text/event-stream` at the acknowledgment and stays open. Frames carry no event name, so each one is `data: ` plus a JSON line, terminated by a blank line. A line starting with `:` is the keepalive TablePro sends every 15 seconds to stop an intermediary timing the connection out; skip it.

Tell the two kinds of frame apart by the envelope. A frame with an `id` equal to your request id is the final JSON-RPC response and the stream is over. A frame with a `method` and no `id` is a notification.

## The notifications

### `notifications/resources/list_changed`

Sent when the set of connections visible to this token changes: one connects, one disconnects, one is blocked for external clients, or its AI policy changes to **Never**.

TablePro compares the visible set against the last one it sent you, so a change that does not move your set produces no notification. A connection you cannot see connecting is not your event.

```json theme={null}
{
  "jsonrpc": "2.0",
  "method": "notifications/resources/list_changed",
  "params": { "_meta": { "io.modelcontextprotocol/subscriptionId": "sub-1" } }
}
```

### `notifications/resources/updated`

Sent when a subscribed connection's schema changes, carrying the URI:

```json theme={null}
{
  "jsonrpc": "2.0",
  "method": "notifications/resources/updated",
  "params": {
    "uri": "tablepro://connections/9f1f0c3e-2e3d-4b14-9c3a-1d2f4ad1f6f1/schema",
    "_meta": { "io.modelcontextprotocol/subscriptionId": "sub-1" }
  }
}
```

It fires on a completed schema load, not on the start of one, so a refresh in flight and a schema that has never loaded both produce nothing. Re-read `tablepro://connections/{id}/schema` when it arrives.

## Closing

The subscription ends when the client closes the connection, cancels the request with `notifications/cancelled`, or the server stops. The final JSON-RPC response is an empty result carrying the subscription id in `_meta`.

There is no deadline on `subscriptions/listen`. It is the one method exempt from the 330-second handler timeout and from the per-caller concurrency limit. The server checks every open subscription for a dropped connection every 15 seconds and closes the ones that went away, so a client that dies without closing does not leak.

## Progress is not a subscription

Progress notifications for a running request travel on that request's own response stream, not here. See [Progress](/external-api/mcp-protocol#progress). Do not open a subscription expecting to receive them.
