Skip to content

fix(everything): drop a disconnected session from the subscriptions map - #4798

Open
voidstackloop wants to merge 1 commit into
modelcontextprotocol:mainfrom
voidstackloop:everything-subscriber-cleanup
Open

voidstackloop wants to merge 1 commit into
modelcontextprotocol:mainfrom
voidstackloop:everything-subscriber-cleanup

Conversation

@voidstackloop

@voidstackloop voidstackloop commented Sep 12, 2026

Copy link
Copy Markdown

subscriptions (a module-level Map<uri, Set<sessionId>> in resources/subscriptions.ts) adds a session id on resources/subscribe and removes it only on an explicit resources/unsubscribe. Nothing removed it when the session itself ended: cleanup(sessionId) (server/index.ts) already stops simulated logging and resource-update timers and cleans up the task store, but never touched subscriptions.

A client that subscribes and disconnects without unsubscribing left its session id in every URI's Set for the life of the process.

Added removeSubscriber(sessionId), which deletes the session from every URI's Set and drops any URI entry left with no subscribers, and called it from cleanup() alongside the existing timer teardown.

Added tests: a session removed via removeSubscriber gets no further simulated update notification, another subscriber to the same URI is unaffected, and calling it for a session with no subscriptions is a no-op. Full test suite (26 tests) and tsc --noEmit pass.

Closes #4710

Description

Publishing Your Server

Note: We are no longer accepting PRs to add servers to the README. Instead, please publish your server to the MCP Server Registry to make it discoverable to the MCP ecosystem.

To publish your server, follow the quickstart guide. You can browse published servers at https://registry.modelcontextprotocol.io/.

Server Details

  • Server:
  • Changes to:

Motivation and Context

How Has This Been Tested?

Breaking Changes

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 Protocol Documentation
  • My changes follows MCP security best practices
  • I have updated the server's README accordingly
  • I have tested this with an LLM client
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have documented all environment variables and configuration options

Additional context

`subscriptions` (a module-level `Map<uri, Set<sessionId>>` in
resources/subscriptions.ts) adds a session id on `resources/subscribe`
and removes it only on an explicit `resources/unsubscribe`. Nothing
removed it when the session itself ended: `cleanup(sessionId)`
(server/index.ts) already stops simulated logging and resource-update
timers and cleans up the task store, but never touched `subscriptions`.

A client that subscribes and disconnects without unsubscribing left
its session id in every URI's Set for the life of the process.

Added `removeSubscriber(sessionId)`, which deletes the session from
every URI's Set and drops any URI entry left with no subscribers, and
called it from `cleanup()` alongside the existing timer teardown.

Added tests: a session removed via `removeSubscriber` gets no further
simulated update notification, another subscriber to the same URI is
unaffected, and calling it for a session with no subscriptions is a
no-op. Full test suite (26 tests) and `tsc --noEmit` pass.

Closes modelcontextprotocol#4710

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
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.

everything: subscriptions map never drops a disconnected session

1 participant