@@ -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 */
@@ -160,12 +183,20 @@ public open class ServerSession(
160183
161184 /* *
162185 * Sends a logging message notification to the client.
186+ * Messages are filtered based on the current logging level set by the client.
187+ * If no logging level is set, all messages are sent.
163188 *
164189 * @param notification The logging message notification.
165190 */
166191 public suspend fun sendLoggingMessage (notification : LoggingMessageNotification ) {
167- logger.trace { " Sending logging message: ${notification.params.data} " }
168- notification(notification)
192+ if (serverCapabilities.logging != null ) {
193+ if (! isMessageIgnored(notification.params.level)) {
194+ logger.trace { " Sending logging message: ${notification.params.data} " }
195+ notification(notification)
196+ } else {
197+ logger.trace { " Filtering out logging message with level ${notification.params.level} " }
198+ }
199+ }
169200 }
170201
171202 /* *
@@ -318,6 +349,7 @@ public open class ServerSession(
318349
319350 Defined .LoggingSetLevel -> {
320351 if (serverCapabilities.logging == null ) {
352+ logger.error { " Server does not support logging (required for $method )" }
321353 throw IllegalStateException (" Server does not support logging (required for $method )" )
322354 }
323355 }
@@ -381,4 +413,19 @@ public open class ServerSession(
381413 instructions = instructions,
382414 )
383415 }
416+
417+ /* *
418+ * Checks if a message with the given level should be ignored based on the current logging level.
419+ *
420+ * @param level The level of the message to check.
421+ * @return true if the message should be ignored (filtered out), false otherwise.
422+ */
423+ private fun isMessageIgnored (level : LoggingLevel ): Boolean {
424+ val current = currentLoggingLevel ? : return false // If no level is set, don't filter
425+
426+ val messageSeverity = loggingLevelSeverity[level] ? : return false
427+ val currentSeverity = loggingLevelSeverity[current] ? : return false
428+
429+ return messageSeverity < currentSeverity
430+ }
384431}
0 commit comments