@@ -32,6 +32,9 @@ import {
3232 ServerRequest ,
3333 ServerResult ,
3434 SUPPORTED_PROTOCOL_VERSIONS ,
35+ LoggingLevel ,
36+ SetLevelRequestSchema ,
37+ LoggingLevelSchema
3538} from "../types.js" ;
3639import Ajv from "ajv" ;
3740
@@ -108,8 +111,36 @@ export class Server<
108111 this . setNotificationHandler ( InitializedNotificationSchema , ( ) =>
109112 this . oninitialized ?.( ) ,
110113 ) ;
114+
115+ if ( this . _capabilities . logging ) {
116+ this . setRequestHandler ( SetLevelRequestSchema , async ( request , extra ) => {
117+ const transportSessionId : string | undefined = extra . sessionId || extra . requestInfo ?. headers [ 'mcp-session-id' ] as string || undefined ;
118+ const { level } = request . params ;
119+ const parseResult = LoggingLevelSchema . safeParse ( level ) ;
120+ if ( transportSessionId && parseResult . success ) {
121+ this . _loggingLevels . set ( transportSessionId , parseResult . data ) ;
122+ }
123+ return { } ;
124+ } )
125+ }
111126 }
112127
128+ // Map log levels by session id
129+ private _loggingLevels = new Map < string , LoggingLevel > ( ) ;
130+
131+ // Map LogLevelSchema to severity index
132+ private readonly LOG_LEVEL_SEVERITY = new Map (
133+ LoggingLevelSchema . options . map ( ( level , index ) => [ level , index ] )
134+ ) ;
135+
136+ // Is a message with the given level ignored in the log level set for the given session id?
137+ private isMessageIgnored = ( level : LoggingLevel , sessionId : string ) : boolean => {
138+ const currentLevel = this . _loggingLevels . get ( sessionId ) ;
139+ return ( currentLevel )
140+ ? this . LOG_LEVEL_SEVERITY . get ( level ) ! < this . LOG_LEVEL_SEVERITY . get ( currentLevel ) !
141+ : false ;
142+ } ;
143+
113144 /**
114145 * Registers new capabilities. This can only be called before connecting to a transport.
115146 *
@@ -121,7 +152,6 @@ export class Server<
121152 "Cannot register capabilities after connecting to transport" ,
122153 ) ;
123154 }
124-
125155 this . _capabilities = mergeCapabilities ( this . _capabilities , capabilities ) ;
126156 }
127157
@@ -324,10 +354,10 @@ export class Server<
324354 if ( result . action === "accept" && result . content ) {
325355 try {
326356 const ajv = new Ajv ( ) ;
327-
357+
328358 const validate = ajv . compile ( params . requestedSchema ) ;
329359 const isValid = validate ( result . content ) ;
330-
360+
331361 if ( ! isValid ) {
332362 throw new McpError (
333363 ErrorCode . InvalidParams ,
@@ -359,8 +389,19 @@ export class Server<
359389 ) ;
360390 }
361391
362- async sendLoggingMessage ( params : LoggingMessageNotification [ "params" ] ) {
363- return this . notification ( { method : "notifications/message" , params } ) ;
392+ /**
393+ * Sends a logging message to the client, if connected.
394+ * Note: You only need to send the parameters object, not the entire JSON RPC message
395+ * @see LoggingMessageNotification
396+ * @param params
397+ * @param sessionId optional for stateless and backward compatibility
398+ */
399+ async sendLoggingMessage ( params : LoggingMessageNotification [ "params" ] , sessionId ?: string ) {
400+ if ( this . _capabilities . logging ) {
401+ if ( ! sessionId || ! this . isMessageIgnored ( params . level , sessionId ) ) {
402+ return this . notification ( { method : "notifications/message" , params} )
403+ }
404+ }
364405 }
365406
366407 async sendResourceUpdated ( params : ResourceUpdatedNotification [ "params" ] ) {
0 commit comments