Skip to content

Conversation

sunerpy
Copy link
Contributor

@sunerpy sunerpy commented Jul 10, 2025

  • Introduced LoggingLevel.ShouldSendTo for log level comparison
  • Added SendLogMessageToSpecificClient to send log notifications to a specific client
  • Added SendLogMessageToClient to send log notifications to the current session client
  • Implemented SessionWithLogging interface for streamableHttpSession
  • Added sessionLogLevelsStore to manage per-session log levels
  • Updated StreamableHTTPServer to support setting and retrieving log levels
  • Added tests covering log notification sending logic and format validation

Description

This PR adds support for sent structured log message notifications in MCP sessions.
This enables server-to-client structured logging over the MCP notification channel, respecting the client’s configured verbosity.

For example:

	hooks.AddAfterCallTool(func(ctx context.Context, id any, message *mm.CallToolRequest, result *mm.CallToolResult) {
		s := ms.ServerFromContext(ctx)
		notification := mm.NewLoggingMessageNotification(
			mm.LoggingLevelError,
			"added tool",
			map[string]any{
				"tool": message.Params,
			},
		)
		err := s.SendLogMessageToClient(ctx, notification)
		if err != nil {
			log.Printf("Failed to send notification: %v", err)
		}
	})

Type of Change

  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • MCP spec compatibility implementation
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation update
  • Code refactoring (no functional changes)
  • Performance improvement
  • Tests only (no functional changes)
  • Other (please describe):

Checklist

  • My code follows the code style of this project
  • I have performed a self-review of my own code
  • I have added tests that prove my fix is effective or that my feature works
  • I have updated the documentation accordingly

MCP Spec Compliance

  • This PR implements a feature defined in the MCP specification
  • Link to relevant spec section: issue
  • Implementation follows the specification exactly

Additional Information

This PR lays the foundation for server-driven structured logging toward clients via MCP protocol. It supports log filtering by level and ensures format consistency for different data . The mechanism respects client preferences and ensures graceful degradation in unsupported or uninitialized cases.

Summary by CodeRabbit

  • New Features

    • Introduced per-session logging level management, allowing sessions to set and retrieve their own log levels.
    • Added support for sending log notifications to clients based on their configured log level.
  • Bug Fixes

    • Improved error handling when sending log messages to uninitialized or unsupported sessions.
  • Tests

    • Added comprehensive tests for logging notification delivery, log level filtering, and notification formatting.
    • Introduced tests to verify session log level management and correct propagation of logging level changes.

- Introduced `LoggingLevel.ShouldSendTo` for log level comparison
- Added `SendLogMessageToSpecificClient` to send log notifications to a specific client
- Added `SendLogMessageToClient` to send log notifications to the current session client
- Implemented `SessionWithLogging` interface for `streamableHttpSession`
- Added `sessionLogLevelsStore` to manage per-session log levels
- Updated `StreamableHTTPServer` to support setting and retrieving log levels
- Added tests covering log notification sending logic and format validation
Copy link
Contributor

coderabbitai bot commented Jul 10, 2025

Walkthrough

This update introduces per-session logging level management and log message notification functionality. It adds log-level filtering, methods for sending log notifications to clients, and a thread-safe store for session log levels. The notification sending logic is refactored for modularity, and comprehensive tests are added for logging-related server behavior.

Changes

Files/Areas Change Summary
mcp/types.go Added levelToInt map for logging level severity, and ShouldSendTo method for log-level comparison.
server/session.go Added methods for log notification construction and sending; refactored notification logic; added log-level filtering for sessions.
server/session_test.go Added tests for sending log messages to clients, log-level filtering, unsupported session handling, and log notification formatting.
server/streamable_http.go Added sessionLogLevelsStore for per-session log levels; integrated into session lifecycle; added getter/setter methods on session objects.
server/streamable_http_test.go Added test for session log level management and propagation after logging level change requests.

Possibly related PRs

Suggested labels

type: enhancement, area: mcp spec, area: sdk

Suggested reviewers

  • pottekkat
  • dugenkui03
  • ezynda3
✨ Finishing Touches
  • 📝 Generate Docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 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.
    • Explain this complex logic.
    • 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 explain this code block.
    • @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 explain its main purpose.
    • @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.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

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 generate sequence diagram to generate a sequence diagram of the changes in 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 (1)
server/session.go (1)

250-250: Address linter suggestion for field access

The static analysis tool suggests using the promoted field directly for cleaner code.

-			method := notification.Notification.Method
+			method := notification.Method
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 2d479bb and 95e9c97.

📒 Files selected for processing (5)
  • mcp/types.go (1 hunks)
  • server/session.go (6 hunks)
  • server/session_test.go (1 hunks)
  • server/streamable_http.go (11 hunks)
  • server/streamable_http_test.go (1 hunks)
🧰 Additional context used
🧠 Learnings (3)
server/session_test.go (2)
Learnt from: octo
PR: mark3labs/mcp-go#149
File: mcptest/mcptest.go:0-0
Timestamp: 2025-04-21T21:26:32.945Z
Learning: In the mcptest package, prefer returning errors from helper functions rather than calling t.Fatalf() directly, giving callers flexibility in how to handle errors.
Learnt from: ezynda3
PR: mark3labs/mcp-go#461
File: server/sampling.go:22-26
Timestamp: 2025-06-30T07:13:17.052Z
Learning: In the mark3labs/mcp-go project, the MCPServer.capabilities field is a struct value (serverCapabilities), not a pointer, so it cannot be nil and doesn't require nil checking. Only pointer fields within the capabilities struct should be checked for nil.
server/streamable_http.go (1)
Learnt from: ezynda3
PR: mark3labs/mcp-go#461
File: server/sampling.go:22-26
Timestamp: 2025-06-30T07:13:17.052Z
Learning: In the mark3labs/mcp-go project, the MCPServer.capabilities field is a struct value (serverCapabilities), not a pointer, so it cannot be nil and doesn't require nil checking. Only pointer fields within the capabilities struct should be checked for nil.
server/session.go (1)
Learnt from: ezynda3
PR: mark3labs/mcp-go#461
File: server/sampling.go:22-26
Timestamp: 2025-06-30T07:13:17.052Z
Learning: In the mark3labs/mcp-go project, the MCPServer.capabilities field is a struct value (serverCapabilities), not a pointer, so it cannot be nil and doesn't require nil checking. Only pointer fields within the capabilities struct should be checked for nil.
🧬 Code Graph Analysis (1)
server/streamable_http.go (2)
mcp/types.go (2)
  • LoggingLevel (751-751)
  • LoggingLevelError (758-758)
server/session.go (2)
  • SessionWithTools (32-40)
  • SessionWithLogging (23-29)
🪛 GitHub Check: lint
server/session.go

[failure] 250-250:
QF1008: could remove embedded field "Notification" from selector (staticcheck)

🪛 GitHub Actions: golangci-lint
server/session.go

[error] 250-250: golangci-lint (staticcheck): could remove embedded field "Notification" from selector (QF1008)

🔇 Additional comments (15)
mcp/types.go (1)

764-783: LGTM!

The logging level severity mapping and comparison logic are correctly implemented. The severity ordering follows the syslog standard (RFC-5424) as documented, and the ShouldSendTo method safely handles unknown levels by returning false.

server/streamable_http_test.go (1)

728-795: LGTM!

The test thoroughly validates the session logging functionality. Good use of hooks to capture the session context and proper synchronization with mutex for thread-safe access.

server/session_test.go (4)

1131-1222: Well-structured test coverage for log message filtering.

The test properly validates that log messages are filtered based on the session's configured log level, ensuring that only messages at or above the minimum severity are sent.


1224-1344: Comprehensive test for sending logs to specific clients.

Good coverage of edge cases including non-existent sessions and uninitialized sessions. The test properly validates error types using errors.Is.


1346-1431: Excellent test for mixed session types.

This test effectively validates the behavior when sessions have different capabilities (logging-supported, logging-unsupported, and uninitialized). The error assertions correctly verify the expected error types.


1433-1509: Thorough validation of log data format preservation.

The test ensures that various data types (strings, maps, errors, nil) are correctly preserved in log notifications. Good coverage of different data formats that might be logged.

server/streamable_http.go (3)

516-547: Thread-safe implementation of session log levels store.

The sessionLogLevelsStore correctly implements thread-safe operations with proper mutex usage. The default log level of LoggingLevelError is a reasonable choice.


132-140: Proper integration of logging levels throughout the session lifecycle.

The session log levels store is correctly initialized, passed to sessions, and cleaned up on deletion. The lifecycle management ensures no memory leaks.

Also applies to: 260-260, 370-370, 473-473


586-597: Clean implementation of SessionWithLogging interface.

The streamableHttpSession properly implements the SessionWithLogging interface by delegating to the shared store. The interface assertions confirm the implementation.

Also applies to: 617-624, 635-638

server/session.go (6)

99-113: LGTM!

The buildLogNotification method correctly constructs a JSON-RPC notification from the logging message parameters, properly mapping all required fields.


115-128: Well-structured log notification implementation!

The method properly validates the session, checks for logging support, and implements log level filtering before sending notifications. Good defensive programming with appropriate error handling.


184-201: LGTM!

The implementation correctly handles session lookup, validation, and log level filtering before sending notifications to specific clients.


217-232: Good refactoring!

The separation of notification building from the sending logic improves code organization and reduces duplication.


266-286: Clean refactoring!

The method now properly delegates to the core notification logic, reducing code duplication while maintaining the same public interface.


289-312: LGTM!

The refactoring successfully reduces code duplication by delegating to the helper method.

- Replaced `notification.Notification.Method` with `notification.Method` to resolve QF1008 from staticcheck
- No functional change; improves code clarity and eliminates linter warning
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

♻️ Duplicate comments (2)
server/session.go (2)

146-146: Fix field access inconsistency

For consistency with the rest of the codebase, access the Method field through the Notification embedded field.

-							"method":    notification.Method,
+							"method":    notification.Notification.Method,

175-175: Fix field access inconsistency

For consistency with the rest of the codebase, access the Method field through the Notification embedded field.

-					"method":    notification.Method,
+					"method":    notification.Notification.Method,
🧹 Nitpick comments (1)
server/session.go (1)

250-250: Consider consistency with field access pattern.

For consistency with the codebase pattern, consider accessing the Method field through the Notification embedded field, similar to the pattern used elsewhere in error handling.

-			method := notification.Method
+			method := notification.Notification.Method
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 95e9c97 and 6fde662.

📒 Files selected for processing (1)
  • server/session.go (6 hunks)
🧰 Additional context used
🧠 Learnings (1)
server/session.go (1)
Learnt from: ezynda3
PR: mark3labs/mcp-go#461
File: server/sampling.go:22-26
Timestamp: 2025-06-30T07:13:17.052Z
Learning: In the mark3labs/mcp-go project, the MCPServer.capabilities field is a struct value (serverCapabilities), not a pointer, so it cannot be nil and doesn't require nil checking. Only pointer fields within the capabilities struct should be checked for nil.
🔇 Additional comments (6)
server/session.go (6)

22-29: Well-designed interface extension.

The SessionWithLogging interface cleanly extends ClientSession with logging capabilities, following Go's composition patterns correctly.


99-113: Clean notification builder implementation.

The buildLogNotification method properly constructs JSON-RPC notifications from LoggingMessageNotification objects with correct field mapping.


115-128: Robust log message sending with proper validation.

The method correctly validates session state, logging support, and log level filtering before sending notifications. The use of ShouldSendTo for level filtering is appropriate.


184-201: Comprehensive validation and log level filtering.

The method properly validates session existence, initialization, logging support, and applies log level filtering before sending notifications. Error handling is appropriate for each validation step.


235-264: Well-extracted core notification logic.

The sendNotificationCore method effectively consolidates notification sending logic, including SSE upgrade handling and proper error handling for blocked channels. Good refactoring to eliminate code duplication.


266-286: Improved notification sending with better error handling.

The refactored method now uses the centralized sendNotificationCore for consistent behavior and error handling across all notification sending methods.

@ezynda3 ezynda3 merged commit ffea75f into mark3labs:main Jul 15, 2025
4 checks passed
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.

2 participants