Skip to content

Answer subscriptions/listen, agreeing to nothing, and close it cleanly (#111) - #127

Merged
TGoodhew merged 1 commit into
mainfrom
issue-111-subscriptions-listen
Jul 31, 2026
Merged

Answer subscriptions/listen, agreeing to nothing, and close it cleanly (#111)#127
TGoodhew merged 1 commit into
mainfrom
issue-111-subscriptions-listen

Conversation

@TGoodhew

Copy link
Copy Markdown
Owner

Closes #111. Last of the conformance block.

SEP-2575 replaces the HTTP GET endpoint and resources/subscribe with subscriptions/listen: one long-lived stream carrying the change notifications a client opted into. We had it falling through to MethodNotFound.

The answer

There is genuinely nothing here to subscribe to — the tool list is fixed at start-up (which is what the listChanged: false we advertise says) and the server exposes no resources or prompts. So the honest answer is neither an error nor an open stream:

  1. Acknowledge with an empty notifications filter. That field is precisely how the spec says a server reports the subset it agreed to honour, so an empty one tells a client "none of what you asked for" in the protocol's own terms.
  2. Then the empty result, which is the spec's graceful closure — the difference between "ended cleanly" and a connection that just dropped.

Holding the stream open instead would promise a message that can never arrive.

Details worth noting

  • The acknowledgement MUST be the first message on the subscription, so it goes out on the outbound channel before the response is returned. There's a test on that ordering — the wrong way round would have a client see a closed subscription before it knew one existed.
  • The subscription id is the request's own JSON-RPC id, whatever its type (a string id stays a string), carried in _meta on both messages.
  • The HTTP transport has no outbound channel — a POST gets one JSON response — so a caller there receives the closure alone. With no notification types agreed, the two messages carry the same information, so nothing is lost. Documented rather than worked around.

Verification

  • 7 new tests — answered not refused; acknowledgement agrees to nothing and carries the subscription id; graceful closure; ordering (ack before response); works with no outbound channel; a string request id; and a guard that no notifications/* is ever sent unasked, which is the rule that matters as the server grows.
  • Full suite green: 402 GpibMcp + 113 Hpgl, 0 failures (Release|x86) — was 395 + 113.

README: "Protocol revisions" covers it, and points at notifications/progress as the stream that actually matters here — request-scoped, so it rides its own request.

#111)

SEP-2575 replaces the HTTP GET endpoint and resources/subscribe with
subscriptions/listen: one long-lived stream carrying the change notifications a
client opted into. We had it falling through to MethodNotFound.

There is genuinely nothing here to subscribe to. The tool list is fixed at
start-up - which is what the listChanged:false we advertise says - and the
server exposes no resources or prompts. So the honest answer is not an error and
not an open stream: acknowledge with an empty `notifications` filter, which is
precisely how the spec says a server reports the subset it agreed to honour, and
then send the empty result that means graceful closure. A client learns what is
supported (nothing) and that the subscription ended cleanly rather than dropping.

Holding the stream open instead would promise a message that can never arrive.

The acknowledgement MUST be the first message on the subscription, so it goes
out on the outbound channel before the response is returned - there is a test on
that ordering, since the wrong way round would have a client see a closed
subscription before it knew one existed. The subscription id is the request's
own JSON-RPC id, whatever its type, carried in _meta on both messages.

The HTTP transport has no outbound channel - a POST gets one JSON response - so
a caller there receives the closure alone. With no notification types agreed the
two messages carry the same information, so nothing is lost.

7 tests, including one asserting no notifications/* is ever sent unasked.
@TGoodhew
TGoodhew merged commit 15456d1 into main Jul 31, 2026
1 check passed
@TGoodhew
TGoodhew deleted the issue-111-subscriptions-listen branch July 31, 2026 16:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

MCP 2026-07-28: answer subscriptions/listen (replaces the HTTP GET stream)

1 participant