@@ -16,6 +16,7 @@ import io.modelcontextprotocol.kotlin.sdk.InitializedNotification
1616import io.modelcontextprotocol.kotlin.sdk.LATEST_PROTOCOL_VERSION
1717import io.modelcontextprotocol.kotlin.sdk.ListRootsRequest
1818import io.modelcontextprotocol.kotlin.sdk.ListRootsResult
19+ import io.modelcontextprotocol.kotlin.sdk.LoggingLevel
1920import io.modelcontextprotocol.kotlin.sdk.LoggingMessageNotification
2021import io.modelcontextprotocol.kotlin.sdk.Method
2122import io.modelcontextprotocol.kotlin.sdk.Method.Defined
@@ -43,22 +44,6 @@ public open class ServerSession(
4344 @Suppress(" ktlint:standard:backing-property-naming" )
4445 private var _onClose : () -> Unit = {}
4546
46- init {
47- // Core protocol handlers
48- setRequestHandler<InitializeRequest >(Method .Defined .Initialize ) { request, _ ->
49- handleInitialize(request)
50- }
51- setNotificationHandler<InitializedNotification >(Method .Defined .NotificationsInitialized ) {
52- _onInitialized ()
53- CompletableDeferred (Unit )
54- }
55- }
56-
57- /* *
58- * The capabilities supported by the server, related to the session.
59- */
60- private val serverCapabilities = options.capabilities
61-
6247 /* *
6348 * The client's reported capabilities after initialization.
6449 */
@@ -71,6 +56,44 @@ public open class ServerSession(
7156 public var clientVersion: Implementation ? = null
7257 private set
7358
59+ /* *
60+ * The capabilities supported by the server, related to the session.
61+ */
62+ private val serverCapabilities = options.capabilities
63+
64+ /* *
65+ * The current logging level set by the client.
66+ * When null, all messages are sent (no filtering).
67+ */
68+ private var currentLoggingLevel: LoggingLevel ? = null
69+
70+ /* *
71+ * Map of LoggingLevel to severity index for comparison.
72+ * Higher index means higher severity.
73+ */
74+ private val loggingLevelSeverity: Map <LoggingLevel , Int > = LoggingLevel .entries.withIndex()
75+ .associate { (index, level) -> level to index }
76+
77+ init {
78+ // Core protocol handlers
79+ setRequestHandler<InitializeRequest >(Defined .Initialize ) { request, _ ->
80+ handleInitialize(request)
81+ }
82+ setNotificationHandler<InitializedNotification >(Defined .NotificationsInitialized ) {
83+ _onInitialized ()
84+ CompletableDeferred (Unit )
85+ }
86+
87+ // Logging level handler
88+ if (options.capabilities.logging != null ) {
89+ setRequestHandler<LoggingMessageNotification .SetLevelRequest >(Defined .LoggingSetLevel ) { request, _ ->
90+ currentLoggingLevel = request.level
91+ logger.debug { " Logging level set to: ${request.level} " }
92+ EmptyRequestResult ()
93+ }
94+ }
95+ }
96+
7497 /* *
7598 * Registers a callback to be invoked when the server has completed initialization.
7699 */
@@ -152,12 +175,20 @@ public open class ServerSession(
152175
153176 /* *
154177 * Sends a logging message notification to the client.
178+ * Messages are filtered based on the current logging level set by the client.
179+ * If no logging level is set, all messages are sent.
155180 *
156181 * @param notification The logging message notification.
157182 */
158183 public suspend fun sendLoggingMessage (notification : LoggingMessageNotification ) {
159- logger.trace { " Sending logging message: ${notification.params.data} " }
160- notification(notification)
184+ if (serverCapabilities.logging != null ) {
185+ if (! isMessageIgnored(notification.params.level)) {
186+ logger.trace { " Sending logging message: ${notification.params.data} " }
187+ notification(notification)
188+ } else {
189+ logger.trace { " Filtering out logging message with level ${notification.params.level} " }
190+ }
191+ }
161192 }
162193
163194 /* *
@@ -310,6 +341,7 @@ public open class ServerSession(
310341
311342 Defined .LoggingSetLevel -> {
312343 if (serverCapabilities.logging == null ) {
344+ logger.error { " Server does not support logging (required for $method )" }
313345 throw IllegalStateException (" Server does not support logging (required for $method )" )
314346 }
315347 }
@@ -373,4 +405,19 @@ public open class ServerSession(
373405 instructions = instructions,
374406 )
375407 }
408+
409+ /* *
410+ * Checks if a message with the given level should be ignored based on the current logging level.
411+ *
412+ * @param level The level of the message to check.
413+ * @return true if the message should be ignored (filtered out), false otherwise.
414+ */
415+ private fun isMessageIgnored (level : LoggingLevel ): Boolean {
416+ val current = currentLoggingLevel ? : return false // If no level is set, don't filter
417+
418+ val messageSeverity = loggingLevelSeverity[level] ? : return false
419+ val currentSeverity = loggingLevelSeverity[current] ? : return false
420+
421+ return messageSeverity < currentSeverity
422+ }
376423}
0 commit comments