Skip to content

Automatic handling of logging level #882

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

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

cliffhall
Copy link
Member

@cliffhall cliffhall commented Aug 18, 2025

Description

  • Add automatic, spec-compliant setLevel request handling to Server class when logging capability is advertised.
  • Update sendLoggingMessage method in Server class to respect current log level.
  • Add sendLoggingMessage passthrough method on McpServer class since it doesn't use inheritance.
  • Update all examples that previously used sendNotification to send log messages to instead use the sendLoggingMessage method so that it can be filtered according to the log level.
  • In src/server/index.ts

    • in constructor
      • if capabilities object has logging, set request handler for SetLevelRequestSchema which
        • gets the session id from the extra param
        • if there is a session id, it maps the the level value from the request params to the session id
        • returns empty object as per spec
    • define private _loggingLevels property mapping a string to a LoggingLevel type
    • define private _levelNames property with an ascending list of the logging levels according to RFC 5424 as per spec. This gives us a lookup to determine if level is greater or less than a target level
    • add private isMessageIgnored method which takes a LoggingLevel and sessionId, returns boolean, and looks up the currently set level for the given session id and the target level, returning true if the target level is below the current level
    • in sendLoggingMessage method,
      • added an optional sessionId argument
      • only process if _capabilities.logging has been declared
      • only send the notification if there is no sessionId OR the params.level value is not ignored for the given session id.
  • In mcp.ts

    • import LoggingMessageNotification
    • add async sendLoggingMessage method with the same signature as the corresponding method in Server class
    • calls the same method in this.server, passing the args
  • In src/examples/server/

    • jsonResponseStreamableHttp.ts
    • simpleSseServer.ts
    • simpleStreamableHttp.ts
    • simpleStatelessStreamableHttp.ts
      • in tool call callback functions that send logging messages
        • remove destructure of sendNotification, we won't use it now
        • destructure the extra param
        • replace sendNotification calls with server.sendLoggingMessage, passing only the params section of the message and extra.sessionId

Motivation and Context

We discovered in this issue in the Inspector repo that when the Inspector sends an setLevel request to a server that has advertised logging support but has not set a listener for logging/setLevel requests, the initialization phase will fail and the server will not connect. Rather than remove the setLevel request, we instead added a toast popup that says Server declares logging capability but doesn't implement method "logging/setLevel". We did this, because in that case, the Inspector is operating in-spec, but arguably, the server is not.

Regarding logging, the spec has the following to say:

Servers that emit log message notifications MUST declare the logging capability

The protocol follows the standard syslog severity levels specified in RFC 5424

To configure the minimum log level, clients MAY send a logging/setLevel request

All of the examples in the SDK that advertise logging capability support actually fail to do so properly. The only example of adding support for logging capability exists in the Everything Server in the servers repo. It is composed of two parts:

It is a lot to ask for every server developer to have to implement this boilerplate functionality, particularly when it could be done automatically by the SDK's Server and McpServer classes.

The examples in the SDK send logging messages, so they must advertise logging capability. However they do not listen for setLevel requests nor implement the ability to respect a requested log level. This means the Inspector will not connect with them. This is the same situation developers face with with their own servers until they add such support.

How Has This Been Tested?

All of the example servers have been refactored to use the sendLoggingMessage method, so they do not have to implement any logic to support log level handling.

In this screen recording, I demonstrate connecting multiple clients to the same server instance of the simpleStreamableHttps.ts example. Its multi-greet tool sends three messages at info level then sends a response. I adjust the debug levels independently for each client then run the tool, showing that the logging level is tracked per session and one session's level does not interfere with the other's.

Breaking Changes

Nope.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • [] Documentation update

Checklist

  • I have read the MCP Documentation
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have added or updated documentation as needed

Additional context

…. Update sendLoggingMessage method to respect current log level.

Add sendLoggingMessage passthrough method on McpServer class since it doesn't use inheritance.

Update examples to use the sendLoggingMessage method so that it can be filtered according to the log level.

* In src/server/index.ts
  - in constructor
    - if capabilities object has logging, set request handler for SetLevelRequestSchema which sets this.logLevel to the level value from the request params and return empty object as per spec
  - define private _logLevel property of type LoggingLevel initialized to "debug"
  - define private _msgLevels property with list of objects with level property set to the ascending logging levels according to RFC 5424 as per spec. This gives us a lookup to determine if level is greater or less than a target level
  - add private isMessageIgnored method which takes a LoggingLevel type arg returns boolean, and looks up the currently set level and the target level, returning true if the target level is below the current level
  - in sendLoggingMessage method, only send the notification if the params.level value is not ignored.

* In mcp.ts
  - import LoggingMessageNotification
  - add async sendLoggingMessage method that returns takes a params object from LoggingMessageNotification, and returns the result of a call to this.server.sendLoggingMessage (since McpServer doesn't extend Server, but rather uses composition.

* In src/examples/server/
  - jsonResponseStreamableHttp.ts
  - simpleSseServer.ts
  - simpleStreamableHttp.ts
  - simpleStatelessStreamableHttp.ts
    - in tool call callback functions that send logging message via the included sendNotification function, replace with calls to server.sendLoggingMessage, passing only the params of the message.
@cliffhall cliffhall requested a review from a team as a code owner August 18, 2025 23:16
@cliffhall cliffhall requested a review from ihrpr August 18, 2025 23:16
@cliffhall cliffhall marked this pull request as draft August 19, 2025 13:41
* In src/server/index.ts
  - in Server class constructor when setting request handler for SetLevelRequestSchema
    - take the sessionId OR 'mcp-session-id' header and store the session id in the _loggingLevels map by session id. Doesn't store the level if there is no session id
  - change _logLevel variable to a Map, string to LoggingLevel type
  - rename _msgLevels array to _levelNames and just make it strings for simplicity
  - in isMessageIgnored function
    - take a sessionId argument
    - change _msgLevels to _levelNames
    - match against the level stored in the _loggingLevels map by session id
  - in sendLoggingLevelMessage,
    - add optional sessionId argument
    - make all action conditional upon _capabilities.logging existing
    - if there is no session id OR if the message is not ignored based on the level and session id, send the notification

* In src/server/mcp.ts
  - in sendLoggingMessage
    - add optional sessionId argument
    - pass sessionId to server.sendLoggingMessage

* In src/examples/server
  - jsonResponseStreamableHttp.ts
  - simpleSseServer.ts
  - simpleStatelessStreamableHttp.ts
  - simpleStreamableHttp.ts
  - sseAndStreamableHttpCompatibleServer.ts
    - update tool callbacks to get the extra param
    - update erver.sendLoggingMessage calls to include extra.sessionId
@cliffhall cliffhall marked this pull request as ready for review August 19, 2025 15:38
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.

1 participant