Skip to content

feat: SEP-2575 subscriptionId value assertion + server-sent cancelled restriction#351

Draft
pja-ant wants to merge 1 commit into
mainfrom
sep-2575-subscription-id-and-cancelled
Draft

feat: SEP-2575 subscriptionId value assertion + server-sent cancelled restriction#351
pja-ant wants to merge 1 commit into
mainfrom
sep-2575-subscription-id-and-cancelled

Conversation

@pja-ant

@pja-ant pja-ant commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

Aligns the SEP-2575 server scenario with the cancellation/subscription clarifications from modelcontextprotocol/modelcontextprotocol#2889:

  • io.modelcontextprotocol/subscriptionId in notification _meta MUST equal the JSON-RPC id of the subscriptions/listen request that opened the stream.
  • Servers MUST NOT send notifications/cancelled for any purpose other than tearing down a subscriptions/listen stream.
  • Servers MUST send notifications/cancelled referencing the listen request id when tearing down that stream — no portable black-box trigger, so traceability excluded.

Check IDs

  • sep-2575-server-tags-subscription-id — strengthened: now also fails when the value does not match the listen request id (string/number normalised).
  • sep-2575-server-cancelled-only-for-subscription — new: flags notifications/cancelled arriving on a non-subscription SSE response stream.

Changes

  • listenToStream now accepts an explicit request id so callers can assert against it.
  • The tools/call probe stream is hoisted and shared between sep-2575-http-server-no-independent-requests-on-stream and the new cancelled check (one fewer round-trip).
  • src/seps/sep-2575.yaml: new check row + excluded row for the server-initiated teardown MUST.
  • stateless.test.ts: spec-compliant fallback echoes the listen id; releaseLock moved onto the mock reader so frame inspection runs; new negative tests for mismatched subscriptionId and stray notifications/cancelled, each with a positive cross-assertion.

npx tsc --noEmit, npm test (295 pass), npm run lint all green.

https://claude.ai/code/session_01Gbqx5LodtAghT5fRYFxeja

… cancelled restriction check (SEP-2575)

Upstream spec PR modelcontextprotocol/modelcontextprotocol#2889 clarifies that
io.modelcontextprotocol/subscriptionId MUST equal the JSON-RPC id of the
subscriptions/listen request, and that servers MUST NOT send
notifications/cancelled for any purpose other than tearing down a
subscriptions/listen stream.

- listenToStream now accepts an explicit request id so callers can assert
  against it; sep-2575-server-tags-subscription-id now also fails when the
  value does not match the listen request id (string/number normalised).
- New check sep-2575-server-cancelled-only-for-subscription flags
  notifications/cancelled arriving on a non-subscription response stream;
  the tools/call probe stream is hoisted and shared with the existing
  no-independent-requests check.
- sep-2575.yaml: add the new check row and an excluded row for the
  server-initiated teardown MUST (no portable black-box trigger).
- stateless.test.ts: spec-compliant fallback now echoes the listen id;
  releaseLock moved onto the mock reader so frame inspection actually runs;
  added negative tests for the mismatched subscriptionId and stray
  notifications/cancelled cases plus positive assertions for each.

Claude-Session: https://claude.ai/code/session_01Gbqx5LodtAghT5fRYFxeja
@pkg-pr-new

pkg-pr-new Bot commented Jun 18, 2026

Copy link
Copy Markdown

Open in StackBlitz

npx https://pkg.pr.new/@modelcontextprotocol/conformance@351

commit: a0cda49

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

1 participant