What's broken?
The spec is ambiguous or self-contradictory
Where in the spec or docs?
|
A server **MUST** send `notifications/cancelled` |
|
referencing a `subscriptions/listen` request ID when it tears down that subscription |
|
stream (see [Subscriptions][subscriptions]). Servers **MUST NOT** send |
|
`notifications/cancelled` for any other purpose. |
What should happen?
The two pages should agree with each other, with the schema and with the SDKs. subscriptions/listen has a declared result type and both SDKs send it, so cancellation.mdx is the page to align: state that cancellation notifications travel from client to server only, that a server does not send notifications/cancelled, and point to Graceful Closure for server-initiated teardown. That means replacing lines 11 to 14 and removing the bullet at lines 71 to 72, in both the 2026-07-28 and draft copies, as #3171 did for subscriptions.mdx. The stdio sentence at schema/draft/schema.ts line 637 and the generated schema.json can be updated in the same change. Happy to open the PR.
What actually happens?
Two pages of the 2026-07-28 revision describe the same event, a server tearing down a subscriptions/listen stream, with different messages and different normative levels, and neither refers to the other. Links pinned to e76e9c57.
cancellation.mdx#L11-L14: "A server MUST send notifications/cancelled referencing a subscriptions/listen request ID when it tears down that subscription stream". Repeated at #L71-L72: "Server-sent cancellation notifications MUST reference a subscriptions/listen request".
subscriptions.mdx#L122-L124, with Graceful Closure at #L128-L136: the server "SHOULD send a successful subscriptions/listen response to signal a graceful end [...], then close the stream".
The same divergence is present in docs/specification/draft/.
How they drifted: #2863 introduced a server-sent notifications/cancelled bounded to stdio; #2889 (merged 2026-06-17) mirrored that wording into cancellation.mdx in commit be09b82e, and a review suggestion then dropped "on stdio" in commit 8792e0b1; #2953 replaced the mechanism in subscriptions.mdx with the subscriptions/listen result in commit 2ffc3fa2, without touching cancellation.mdx.
schema.ts#L637 still describes the server sending this notification "On stdio" only, so the unqualified MUST has no counterpart in the schema, while SubscriptionsListenResult is a declared type with a required _meta.
Both SDKs follow subscriptions.mdx: typescript-sdk packages/server/src/server/listenRouter.ts lines 171 to 187 and 412 to 429 (5119ee7f), and python-sdk src/mcp/server/subscriptions.py lines 188, 241 and 243 to 254 (7bb486a1) send the result and no server-side notifications/cancelled, on either transport.
Anything else?
I searched open and closed issues and PRs and found no earlier report of this.
AI disclosure, per AI_POLICY.md: this issue was researched and drafted primarily with Claude Code, under my direction and reviewed by me; my replies here may be AI-assisted as well.
What's broken?
The spec is ambiguous or self-contradictory
Where in the spec or docs?
modelcontextprotocol/docs/specification/2026-07-28/basic/patterns/cancellation.mdx
Lines 11 to 14 in e76e9c5
What should happen?
The two pages should agree with each other, with the schema and with the SDKs.
subscriptions/listenhas a declared result type and both SDKs send it, socancellation.mdxis the page to align: state that cancellation notifications travel from client to server only, that a server does not sendnotifications/cancelled, and point to Graceful Closure for server-initiated teardown. That means replacing lines 11 to 14 and removing the bullet at lines 71 to 72, in both the2026-07-28anddraftcopies, as #3171 did forsubscriptions.mdx. The stdio sentence atschema/draft/schema.tsline 637 and the generatedschema.jsoncan be updated in the same change. Happy to open the PR.What actually happens?
Two pages of the 2026-07-28 revision describe the same event, a server tearing down a
subscriptions/listenstream, with different messages and different normative levels, and neither refers to the other. Links pinned toe76e9c57.cancellation.mdx#L11-L14: "A server MUST sendnotifications/cancelledreferencing asubscriptions/listenrequest ID when it tears down that subscription stream". Repeated at#L71-L72: "Server-sent cancellation notifications MUST reference asubscriptions/listenrequest".subscriptions.mdx#L122-L124, with Graceful Closure at#L128-L136: the server "SHOULD send a successfulsubscriptions/listenresponse to signal a graceful end [...], then close the stream".The same divergence is present in
docs/specification/draft/.How they drifted: #2863 introduced a server-sent
notifications/cancelledbounded to stdio; #2889 (merged 2026-06-17) mirrored that wording intocancellation.mdxin commitbe09b82e, and a review suggestion then dropped "on stdio" in commit8792e0b1; #2953 replaced the mechanism insubscriptions.mdxwith thesubscriptions/listenresult in commit2ffc3fa2, without touchingcancellation.mdx.schema.ts#L637still describes the server sending this notification "On stdio" only, so the unqualified MUST has no counterpart in the schema, whileSubscriptionsListenResultis a declared type with a required_meta.Both SDKs follow
subscriptions.mdx:typescript-sdkpackages/server/src/server/listenRouter.tslines 171 to 187 and 412 to 429 (5119ee7f), andpython-sdksrc/mcp/server/subscriptions.pylines 188, 241 and 243 to 254 (7bb486a1) send the result and no server-sidenotifications/cancelled, on either transport.Anything else?
I searched open and closed issues and PRs and found no earlier report of this.
AI disclosure, per
AI_POLICY.md: this issue was researched and drafted primarily with Claude Code, under my direction and reviewed by me; my replies here may be AI-assisted as well.