Skip to content

Add per-session notifications handling #46

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 18, 2025

Conversation

torkve
Copy link
Contributor

@torkve torkve commented Mar 8, 2025

This feature removes global notification channel and notification context, and introduces per-session notification channels.
It also simplifies notification processing in transports as each session worker always receives notifications only for its session.

This fixes #42

Summary by CodeRabbit

  • New Features

    • Enhanced notification delivery across client sessions for more timely progress updates.
    • Introduced static session support to improve notifications for single-client connections.
  • Refactor

    • Reworked session management and notification routing to ensure more consistent client communication.
  • Tests

    • Added comprehensive tests to verify proper notification handling and session functionality, including scenarios with varying active session states.

Copy link
Contributor

coderabbitai bot commented Mar 8, 2025

Walkthrough

The pull request updates the notification handling mechanism across several components. In the examples, the ctx parameter is now passed to SendNotificationToClient calls. In the server package, a new ClientSession interface is introduced to streamline session management and notifications. This update also removes legacy mutex handling, adds session registration methods, and revises notifications delivery to active clients. Corresponding tests have been updated and new tests added to validate these changes. Additionally, session management enhancements have been applied to the SSE and Stdio servers.

Changes

Files Change Summary
examples/everything/main.go Updated calls to SendNotificationToClient in handleSendNotification and handleLongRunningOperationTool functions to include the ctx parameter.
server/server.go Introduced the ClientSession interface (with NotificationChannel() and SessionID() methods), added context key management, replaced mutex handling, and implemented new methods: RegisterSession, UnregisterSession, and sendNotificationToAllClients; updated WithContext, SendNotificationToClient, AddTools, and DeleteTools to use the new session infrastructure.
server/server_test.go Modified the TestMCPServer_Tools function by updating function signatures to handle notifications via a channel and replaced the old notification type; added TestMCPServer_SendNotificationToClient to validate the new notification delivery process based on session state.
server/sse.go, server/stdio.go In sse.go, added sessionID and notificationChannel fields to sseSession along with corresponding methods, and updated notification handling in handleSSE and handleMessage; in stdio.go, introduced the stdioSession type with its dedicated methods and registered a static session instance in the Listen method to streamline stdio notification processing.

Possibly related PRs

Suggested reviewers

  • ezynda3

Tip

⚡🧪 Multi-step agentic review comment chat (experimental)
  • We're introducing multi-step agentic chat in review comments. This experimental feature enhances review discussions with the CodeRabbit agentic chat by enabling advanced interactions, including the ability to create pull requests directly from comments.
    - To enable this feature, set early_access to true under in the settings.

📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f416918 and 3a67a53.

📒 Files selected for processing (5)
  • examples/everything/main.go (2 hunks)
  • server/server.go (6 hunks)
  • server/server_test.go (10 hunks)
  • server/sse.go (3 hunks)
  • server/stdio.go (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • examples/everything/main.go
  • server/stdio.go
  • server/server.go
🔇 Additional comments (10)
server/sse.go (5)

23-23: Great implementation of the session-specific notification channel!

The new fields and accessor methods for sseSession properly implement the ClientSession interface, which is verified with the type assertion. This change aligns well with the PR objective of moving from global notification handling to per-session notifications.

Also applies to: 31-37, 39-39


181-189: Good initialization of the session with notification handling!

The session initialization now includes a session ID and a dedicated notification channel, which is properly buffered to prevent blocking during high notification volume.


194-199: Error handling for RegisterSession added correctly!

You've properly implemented error handling for the session registration process, addressing the previous review comment. The error message is clear and the HTTP status code is appropriate.


204-213: Well-structured notification handling!

The notification processing has been updated to use the session-specific notification channel instead of the global one. This approach ensures each session only receives notifications relevant to it, improving the overall efficiency.


268-272: Context setup updated for per-session notifications!

The context setup now correctly uses the session object directly, which allows downstream handlers to access the session information for notification delivery.

server/server_test.go (5)

155-176: Good test case for notifications without active sessions!

This test case validates that no notifications are sent when there are no active sessions, which is an important edge case to cover when implementing per-session notifications.


198-204: Fixed assertion for notification method!

The assertion is now correctly checking notifications[0].Method instead of the previously incorrect notifications[0].Notification.Method, addressing the issue from the previous review.


228-237: Thorough testing of multiple active sessions!

The test case effectively validates that each active session receives its own notification, confirming that the per-session notification handling works correctly even with multiple concurrent sessions.


476-542: Excellent test coverage for SendNotificationToClient!

The new test function thoroughly covers various notification scenarios:

  1. No active sessions - validating error handling
  2. Active sessions - ensuring notifications are properly sent
  3. Blocked channels - testing error handling for full channels

This comprehensive testing will help ensure the reliability of the notification system.


965-979: Well-implemented fake session for testing!

The fakeSession struct properly implements the ClientSession interface with its required methods, providing a clean way to test session-related functionality without needing actual client connections.

✨ Finishing Touches
  • 📝 Generate Docstrings

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (4)
server/server_test.go (2)

180-183: Check error return value from RegisterSession in tests

The error return value from RegisterSession should be checked, even in test code.

-				server.RegisterSession(&fakeSession{
-					sessionID:           "test",
-					notificationChannel: notificationChannel,
-				})
+				err := server.RegisterSession(&fakeSession{
+					sessionID:           "test",
+					notificationChannel: notificationChannel,
+				})
+				require.NoError(t, err)
🧰 Tools
🪛 golangci-lint (1.62.2)

180-180: Error return value of server.RegisterSession is not checked

(errcheck)


209-213: Check error return value from RegisterSession in loop

Similar to above, the error return value from RegisterSession should be checked within the loop.

-					server.RegisterSession(&fakeSession{
-						sessionID:           fmt.Sprintf("test%d", i),
-						notificationChannel: notificationChannel,
-					})
+					err := server.RegisterSession(&fakeSession{
+						sessionID:           fmt.Sprintf("test%d", i),
+						notificationChannel: notificationChannel,
+					})
+					require.NoError(t, err)
🧰 Tools
🪛 golangci-lint (1.62.2)

209-209: Error return value of server.RegisterSession is not checked

(errcheck)

server/server.go (2)

125-149: Potential data loss when broadcasting notifications
Currently, the non-blocking send with a default case will silently drop notifications if a session’s channel is backlogged. Consider adding a mechanism for buffering or queuing notifications so they are not lost when clients temporarily cannot consume messages.


153-158: Non-blocking send may drop individual client notifications
Similar to the broadcast scenario, the default branch can lead to lost notifications if the channel is blocked. If guaranteed delivery is important, you may consider adding a buffer or alternative queuing strategy.

Also applies to: 173-173

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 258aee9 and 3cddf41.

📒 Files selected for processing (5)
  • examples/everything/main.go (2 hunks)
  • server/server.go (6 hunks)
  • server/server_test.go (13 hunks)
  • server/sse.go (3 hunks)
  • server/stdio.go (2 hunks)
🧰 Additional context used
🪛 golangci-lint (1.62.2)
server/sse.go

160-160: Error return value of s.server.RegisterSession is not checked

(errcheck)

server/stdio.go

73-73: Error return value of s.server.RegisterSession is not checked

(errcheck)

server/server_test.go

180-180: Error return value of server.RegisterSession is not checked

(errcheck)


209-209: Error return value of server.RegisterSession is not checked

(errcheck)


240-240: Error return value of server.RegisterSession is not checked

(errcheck)

🔇 Additional comments (21)
examples/everything/main.go (2)

303-303: Parameter addition looks good

The context parameter is now passed to SendNotificationToClient which aligns with the per-session notification handling approach introduced in this PR.


340-340: Parameter addition looks good

The context parameter is now correctly passed to SendNotificationToClient in the long-running operation tool handler.

server/sse.go (6)

21-22: Good addition of session-specific fields

The sessionID and notificationChannel fields enable per-session notification handling, which aligns with the PR objective of removing global notification channels.


25-31: ClientSession interface implementation

These methods properly expose the session ID and notification channel, implementing the ClientSession interface.


33-33: Good compile-time interface check

This static assertion ensures that sseSession properly implements the ClientSession interface.


155-156: Fields properly initialized

The session ID and notification channel fields are correctly initialized during session creation.


168-177: Using per-session notification channel

This code now correctly uses the session-specific notification channel instead of a global one, which improves encapsulation and aligns with the PR goals.


233-233: Context properly set with session

The context is now properly set with the session information for the request handling.

server/stdio.go (2)

25-42: Good implementation of ClientSession for stdio

The stdioSession struct and its methods properly implement the ClientSession interface for stdio connections. The singleton pattern makes sense since stdio only supports a single client.


83-93: Using per-session notification channel

This code now correctly uses the session-specific notification channel instead of a global one, consistent with the changes in the sse implementation.

server/server_test.go (3)

147-153: Updated test function signatures

The test function signatures have been updated to accommodate the new notification handling mechanism, passing notification channels to the action and validate functions.


472-538: Great test coverage for SendNotificationToClient

This new test function thoroughly tests the SendNotificationToClient method across multiple scenarios:

  1. No active session
  2. With an active session
  3. With a blocked notification channel

This ensures the new per-session notification mechanism works correctly under different conditions.


892-905: Good test helper implementation

The fakeSession type properly implements the ClientSession interface for testing purposes, including the compile-time interface check.

server/server.go (8)

49-55: Well-defined interface for decoupled session-based notifications
This interface is concise and clearly separates session management concerns from the server. The use of a send-only channel for notifications is an effective way to prevent accidental reads on the receiving side.


57-59: Good practice for context key definition
Using an empty struct as a context key helps avoid key collisions and keeps the usage clean.


60-66: Helper function for extracting session from context
Cleanly checks if the context contains a valid session and returns nil otherwise, which aligns well with typical usage patterns.


99-105: Context wrapping for session is straightforward
Storing the ClientSession via context.WithValue is a standard approach and fits well into the rest of the codebase.


107-116: Safe session registration with concurrency awareness
Using LoadOrStore on sync.Map effectively prevents duplicate registrations and ensures thread-safety for session management.


118-124: Simple and effective session unregistration
Removing sessions by their ID cleanly completes the session lifecycle management with minimal overhead.


526-526: Automatic tool list change notification
Notifying all clients of tool additions right after server initialization is logical and keeps sessions updated in real time.


549-549: Consistent notification upon tool deletion
This mirrors the addition workflow, ensuring all sessions receive an up-to-date tool list.

@torkve torkve mentioned this pull request Mar 8, 2025
@torkve torkve force-pushed the issue42-notifications branch from 3cddf41 to 67c327e Compare March 8, 2025 21:45
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
server/sse.go (1)

155-156: Buffer size consistency consideration

The hardcoded buffer size (100) is consistent with other channel buffer sizes in the codebase. This is appropriate for most use cases, but consider making this configurable if you anticipate high-volume notification scenarios.

server/stdio.go (1)

25-25: Fix typo in comment

There's a minor typo in the comment.

-// stdioSssion is a static client session, since stdio has only one client.
+// stdioSession is a static client session, since stdio has only one client.
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3cddf41 and 67c327e.

📒 Files selected for processing (5)
  • examples/everything/main.go (2 hunks)
  • server/server.go (6 hunks)
  • server/server_test.go (13 hunks)
  • server/sse.go (3 hunks)
  • server/stdio.go (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • examples/everything/main.go
  • server/server.go
🔇 Additional comments (15)
server/sse.go (6)

21-22: Improved architecture with per-session notification channels

The addition of these session-specific fields improves isolation between sessions and makes the system more modular. This aligns well with the PR objective of enhancing notification handling.


25-31: Good implementation of accessor methods

These accessor methods properly implement the required ClientSession interface, providing controlled access to the session's identifier and notification channel.


33-33: Good practice: Using type assertion to verify interface compliance

This compile-time check ensures that sseSession properly implements the ClientSession interface.


162-166: Properly implemented error handling for RegisterSession

Good implementation of error handling for RegisterSession and proper cleanup with deferred UnregisterSession. This addresses the issue raised in the previous review.


172-181: Improved notification handling with session-specific channels

The notification handling now uses the per-session channel instead of a global channel, which aligns with the PR objective of simplifying notification processing in transports.


237-237: Updated context handling to use the session directly

This change streamlines context creation by directly using the session object, which is more direct and less error-prone than using separate context components.

server/stdio.go (3)

26-42: Good implementation of per-session notification for stdio

The stdioSession implementation with a static instance is a clean approach for stdio which only supports a single client. The static instance with its notification channel properly isolates the stdio session from others.


72-76: Properly implemented error handling for RegisterSession

Good implementation of error handling for RegisterSession and proper cleanup with deferred UnregisterSession. This addresses the issue raised in the previous review.


84-94: Improved notification handling with session-specific channels

The notification handling now properly uses the stdioSessionInstance's notification channel instead of a global channel, which aligns with the PR objective of making session workers receive only notifications relevant to their specific session.

server/server_test.go (6)

150-152: Updated test signatures to accommodate per-session notifications

The test function signatures have been appropriately updated to work with the new per-session notification system, enabling more thorough testing of notification handling.


155-175: Good test case: Testing with no active sessions

This test case verifies that no notifications are sent when there are no active sessions, which is an important edge case to test.


178-205: Good test case: Testing with a single active session

This test case properly verifies notification delivery with a single active session.


207-238: Good test case: Testing with multiple active sessions

This test case ensures that notifications are properly delivered to multiple active sessions, which is crucial for verifying the scalability of the notification system.


476-542: Comprehensive test for SendNotificationToClient

The added test function thoroughly tests the SendNotificationToClient method under various conditions: no active session, active session, and blocked notification channel. This is essential for ensuring robust notification handling.


896-909: Well-designed test helper: fakeSession implementation

The fakeSession type is a clean and minimal implementation of the ClientSession interface for testing purposes, making the tests more readable and maintainable.

@torkve torkve force-pushed the issue42-notifications branch from 67c327e to 4697e96 Compare March 8, 2025 21:56
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 67c327e and 4697e96.

📒 Files selected for processing (5)
  • examples/everything/main.go (2 hunks)
  • server/server.go (6 hunks)
  • server/server_test.go (13 hunks)
  • server/sse.go (3 hunks)
  • server/stdio.go (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • examples/everything/main.go
  • server/sse.go
  • server/stdio.go
  • server/server.go
🔇 Additional comments (9)
server/server_test.go (9)

6-6: Added necessary imports for enhanced test functionality.

The addition of the fmt package for string formatting and require from testify for more strict assertions improves the testing capabilities.

Also applies to: 12-12


147-168: LGTM! Improved test structure with session-based notifications.

The test function has been updated to accommodate the new per-session notification mechanism, testing the behavior when no active sessions are present. This correctly verifies that no notifications are sent when there are no active sessions.


177-204: Well-implemented test for single active session notifications.

This test case properly verifies that when a single session is registered, exactly one notification is sent through that session's channel. The test correctly registers a fake session with a notification channel and validates that the tools list changed notification is received.


206-237: Good coverage for multiple session notifications.

This test case thoroughly verifies that each active session receives its own notification when tools are updated. The loop creating multiple sessions with separate notification channels ensures comprehensive coverage of this scenario.


239-264: Successfully adapted AddTool test to use session-based notifications.

The test case for AddTool has been properly updated to work with the new per-session notification approach, correctly verifying that multiple notifications are sent when tools are added individually.


305-309: Properly set up notification channel and collection for testing.

The test now correctly creates a buffered notification channel and prepares an empty slice to collect notifications, then passes the channel to the action function for per-session notification handling.


311-312: Channel receiving correctly updated.

The notification collection code has been updated to use the new notification type directly, which is consistent with the per-session notification approach.


476-542: Excellent new test for session-based client notifications.

This comprehensive test validates the SendNotificationToClient functionality with three important scenarios:

  1. No active session - correctly verifies an error is returned
  2. Active session - validates notifications are properly sent to the session's channel
  3. Blocked channel - confirms the appropriate error handling when a notification channel is full

The test covers all key aspects of the new per-session notification mechanism.


896-910: Well-designed fake session implementation.

The fakeSession struct and its methods provide a clean implementation of the ClientSession interface for testing purposes. This implementation includes both the session identifier and notification channel, with proper accessor methods.

@torkve torkve force-pushed the issue42-notifications branch 2 times, most recently from 71ca83f to f416918 Compare March 9, 2025 22:31
@ezynda3 ezynda3 self-assigned this Mar 10, 2025
@torkve torkve force-pushed the issue42-notifications branch from f416918 to 3a67a53 Compare March 12, 2025 20:06
@torkve
Copy link
Contributor Author

torkve commented Mar 17, 2025

@ezynda3 is there anything else needed from me here?

@ezynda3
Copy link
Contributor

ezynda3 commented Mar 18, 2025

gtg

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.

Where does notification go?
3 participants