Skip to content

docs(servers): document resources/subscribe serving; exercise subscriptions in the resources example#2413

Merged
felixweinberger merged 4 commits into
mainfrom
fweinberger/resources-subscribe-docs
Jul 2, 2026
Merged

docs(servers): document resources/subscribe serving; exercise subscriptions in the resources example#2413
felixweinberger merged 4 commits into
mainfrom
fweinberger/resources-subscribe-docs

Conversation

@felixweinberger

Copy link
Copy Markdown
Contributor

The server side of per-resource subscriptions was undocumented: docs/servers/resources.md said nothing about resources/subscribe, and the SDK (by design, as in v1.x) leaves the bookkeeping to the application. This adds the missing section and turns the resources example story into the running reference for it.

Motivation and Context

A client-side page covers the subscribe fallback, and notifications.md covers the 2026-07-28 listen/notifier path — but nothing documented what a server must do for 2025-era subscribers: advertise resources: { subscribe: true }, route the two verbs, track subscribed URIs per connection, and send notifications/resources/updated to subscribers only. Real-world interop testing against a deployed v2 server surfaced this as a gap: the pattern is easy to get subtly wrong (unsolicited updates, cross-connection leakage) and there was no reference to copy.

Changes:

  • docs/servers/resources.md: new "Serve per-resource subscriptions" section, synced from an executable companion region; era info-box pointing the 2026-07-28 path at notifications.md; recap bullet.
  • examples/guides/servers/resources.examples.ts: the new region plus a harness that asserts the section's claims — exactly one resources/updated after subscribe, none after unsubscribe — via a 2025-era in-memory client.
  • examples/resources: adds a mutable counter://value resource and an increment tool with era-split delivery (in-band to 2025 subscribers and stdio connections; published on the handler's notifier for the listen streams other HTTP requests hold open). The client subscribes era-split (subscriptions/listen on 2026-07-28, resources/subscribe on 2025), asserts the notification and the re-read, and skips the delivery assertion on per-request legacy HTTP, which has no channel to carry it.
  • Cross-reference from docs/servers/notifications.md; story and matrix README rows.

How Has This Been Tested?

  • All four resources story legs (stdio/http × modern/legacy) pass under scripts/examples/run-examples.ts.
  • The docs companion harness runs green (npx tsx guides/servers/resources.examples.ts) and self-verifies the page's claims.
  • pnpm sync:snippets --check, examples typecheck + lint, and the docs build all pass.

Breaking Changes

None.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update

Checklist

  • I have read the MCP Documentation
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have added or updated documentation as needed

Additional context

The example intentionally demonstrates the delivery matrix per serving mode rather than hiding it: connection-oriented entries announce in-band, per-request HTTP publishes on the entry's notifier, and stateless legacy HTTP cannot deliver — the client encodes that last fact by skipping the assertion on exactly that leg.

…ptions in the resources example

The server side of per-resource subscriptions was undocumented. resources.md
gains a "Serve per-resource subscriptions" section — advertise the capability,
track subscribed URIs per connection, deliver resources/updated to subscribers
only — synced from an executable companion region whose harness verifies the
claims (one notification after subscribe, none after unsubscribe), with a
cross-reference from notifications.md.

The resources example becomes the running reference: a mutable counter://value
resource and an increment tool, announcing changes in-band to 2025-era
subscribers and stdio connections, and on the handler's notifier for the
listen streams other HTTP requests hold open. The client subscribes via
subscriptions/listen (2026-07-28) or resources/subscribe (2025), asserts the
notifications/resources/updated it produces, and skips the delivery assertion
on per-request legacy HTTP, which has no channel to carry it.
@felixweinberger felixweinberger requested a review from a team as a code owner July 2, 2026 11:04
@changeset-bot

changeset-bot Bot commented Jul 2, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 6da9627

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@pkg-pr-new

pkg-pr-new Bot commented Jul 2, 2026

Copy link
Copy Markdown

Open in StackBlitz

@modelcontextprotocol/client

npm i https://pkg.pr.new/@modelcontextprotocol/client@2413

@modelcontextprotocol/codemod

npm i https://pkg.pr.new/@modelcontextprotocol/codemod@2413

@modelcontextprotocol/core

npm i https://pkg.pr.new/@modelcontextprotocol/core@2413

@modelcontextprotocol/server

npm i https://pkg.pr.new/@modelcontextprotocol/server@2413

@modelcontextprotocol/server-legacy

npm i https://pkg.pr.new/@modelcontextprotocol/server-legacy@2413

@modelcontextprotocol/express

npm i https://pkg.pr.new/@modelcontextprotocol/express@2413

@modelcontextprotocol/fastify

npm i https://pkg.pr.new/@modelcontextprotocol/fastify@2413

@modelcontextprotocol/hono

npm i https://pkg.pr.new/@modelcontextprotocol/hono@2413

@modelcontextprotocol/node

npm i https://pkg.pr.new/@modelcontextprotocol/node@2413

commit: 6da9627

Comment thread docs/servers/resources.md Outdated
Comment thread examples/resources/client.ts
Comment thread examples/resources/client.ts
felixweinberger and others added 2 commits July 2, 2026 12:16
…nable assertion in the client

The subscriptions section now states that the pattern needs a connection
outliving the subscribe call and that the stateless legacy HTTP fallback
discards the tracking set with the per-request instance; the closing sentence
says exactly what each example leg asserts. The client clears the race timer
so the process exits promptly, and asserts the re-read against the value the
increment tool returned so the story re-runs against a long-lived server.
Comment thread docs/servers/resources.md
… the notifier

The era info-box described only the createMcpHandler path; on stdio the entry
routes the instance's own sendResourceUpdated call onto matching listen
streams, so a dual-era server must make that call on 2026-07-28 connections
where the subscribe set is always empty. The prose now states both entries'
behavior and names the era-or-subscribed guard the resources example uses.

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All prior review feedback has been addressed in 9739542 and 6da9627 — this is docs and examples only, so approving.

Extended reasoning...

Overview

This PR is documentation and examples only: a new "Serve per-resource subscriptions" section in docs/servers/resources.md (synced from an executable companion region), a cross-reference in docs/servers/notifications.md, and an extension of the resources example story (mutable counter://value resource, increment tool, era-split subscription client). No SDK package source code is touched.

Security risks

None. The changes do not touch auth, transports, protocol handling, or any published package code. The example server tracks subscription URIs per connection in a Set, which is the pattern the docs recommend and does not introduce cross-connection leakage.

Level of scrutiny

Low-to-moderate: prose accuracy and example correctness are the main concerns, and both were exercised in earlier review rounds. The three earlier review comments (missing serving-mode caveat, uncleared 8s timer keeping the event loop alive, hard-coded counter assertion breaking re-runs) and the follow-up on the era info-box overstating the handler.notify path on stdio were all addressed by the author in commits 9739542 and 6da9627, and the preloaded file contents confirm the fixes are present (timer cleared in a finally, re-read asserted against the tool's returned text, serving-mode caveat and dual-era guard sentence added, info-box reworded for the serveStdio delivery path).

Other factors

The example story is self-verifying and runs in CI across all four transport×era legs via run-examples.ts, and the docs companion harness asserts the section's claims (exactly one resources/updated after subscribe, none after unsubscribe). No changeset is needed since only @mcp-examples/* private packages and docs change. The bug hunting system found no issues on the latest revision.

@felixweinberger felixweinberger merged commit ddf6cc1 into main Jul 2, 2026
22 checks passed
@felixweinberger felixweinberger deleted the fweinberger/resources-subscribe-docs branch July 2, 2026 13:18
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.

1 participant