Add `logging` support
Motivation and Context
A server can send structured logging messages to the client. https://modelcontextprotocol.io/specification/2025-06-18/server/utilities/logging#logging
Logging was specified in the 2024-11-05 specification, but since it was not supported in ruby-sdk, I implemented it. https://modelcontextprotocol.io/specification/2024-11-05/server/utilities/logging
I also made it possible to output a simple notification message in the examples.
How Has This Been Tested?
- [x] Check existing and added test cases for this case
- [x] Check a sse server of examples can send logging message to the client, for more details, see below
Server
Press Ctrl+C to stop the server
Puma starting in single mode...
* Puma version: 6.6.0 ("Return to Forever")
* Ruby version: ruby 3.4.2 (2025-02-15 revision d2930f8e7a) +PRISM [arm64-darwin24]
* Min threads: 0
* Max threads: 5
* Environment: development
* PID: 67186
* Listening on http://127.0.0.1:9393
* Listening on http://[::1]:9393
Use Ctrl-C to stop
[MCP] Request: initialize (id: init-1)
[SSE] INFO 17:44:56.927 - New client initializing session
[MCP] Response: success (id: init-1)
[SSE] INFO 17:44:56.927 - Session created: 4821e46a-b75e-4469-8e69-8b4eaa4554de
::1 - - [02/Nov/2025:17:44:56 +0900] "POST /mcp HTTP/1.1" 200 - 0.0002
[MCP] Request: logging/setLevel (id: 18042833-4f74-4008-beaf-2795fd9bc4b4)
[MCP] Response: success (id: 18042833-4f74-4008-beaf-2795fd9bc4b4)
::1 - - [02/Nov/2025:17:44:56 +0900] "POST /mcp HTTP/1.1" 200 - 0.0001
[SSE] INFO 17:44:56.929 - SSE connection request for session: 4821e46a-b75e-4469-8e69-8b4eaa4554de
[SSE] INFO 17:44:56.929 - SSE stream established
::1 - - [02/Nov/2025:17:44:56 +0900] "GET /mcp HTTP/1.1" 200 - 0.0001
[MCP] Request: tools/call (id: de0de93c-b33d-4747-bb89-1157418bb06d)
[SSE] INFO 17:45:16.081 - Returning notification message: logging support
[SSE] INFO 17:45:16.082 - Response sent via SSE stream
::1 - - [02/Nov/2025:17:45:16 +0900] "POST /mcp HTTP/1.1" 200 - 0.0010
Client
% ruby examples/streamable_http_client.rb
=== MCP SSE Test Client ===
[CLIENT] INFO 17:44:56.925 - Initializing session...
[CLIENT] INFO 17:44:56.928 - Session initialized: 4821e46a-b75e-4469-8e69-8b4eaa4554de
[CLIENT] INFO 17:44:56.928 - Server info: {"name" => "sse_test_server", "version" => "0.1.0"}
[CLIENT] INFO 17:44:56.928 - Connecting to SSE stream...
[CLIENT] INFO 17:44:56.929 - SSE stream connected successfully
=== Available Actions ===
1. Send custom notification
2. Test echo
3. List tools
0. Exit
Choose an action:
1
Enter notification message: logging support
Enter delay in seconds (0 for immediate):
[CLIENT] INFO 17:45:16.082 - SSE data: {"jsonrpc":"2.0","id":"de0de93c-b33d-4747-bb89-1157418bb06d","result":{"content":[{"type":"text","text":"Notification: logging support (timestamp: 2025-11-02T17:45:16+09:00)"}],"isError":false}}
[CLIENT] INFO 17:45:16.082 - SSE data: {"jsonrpc":"2.0","method":"notifications/message","params":{"data":{"details":"Response accepted and sent via SSE"},"level":"info"}}
[CLIENT] INFO 17:45:16.082 - Notification sent successfully
=== Available Actions ===
1. Send custom notification
2. Test echo
3. List tools
0. Exit
Choose an action:
Breaking Changes
None
Types of changes
- [ ] Bug fix (non-breaking change which fixes an issue)
- [x] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to change)
- [x] Documentation update
Checklist
- [x] I have read the MCP Documentation
- [x] My code follows the repository's style guidelines
- [x] New and existing tests pass locally
- [x] I have added appropriate error handling
- [x] I have added or updated documentation as needed
Additional context
@dak2 Oops, can you rebase with the latest master to resolve the conflicts?
@koic Thank you for letting me know! The conflict has been resolved. Could you please review it again?
Oops, sorry if my understanding of the specification and this implementation is different. As I understand it, with logging/setLevel, only messages at the specified level or higher should be sent from the server to the client as notifications/message. In other words, if the level error is specified, messages at info or warning level should not be notified.
I believe "Only sends error level and above" in the "Message Flow" section corresponds to this.
https://modelcontextprotocol.io/specification/2025-06-18/server/utilities/logging#message-flow
It seems to me that the current PR is not implemented in this way. Could you check?
@koic Thank you for checking it!
Oops, I missed it! That's true. This implementation doesn't meet a logging specification. I'll implement it soon when I have free time.
@koic
I implemented the logic to determine whether or not to send a notification based on level. Could you please review it again?
https://github.com/modelcontextprotocol/ruby-sdk/compare/ef5049bab808dec719765a771c04e7c897c2a8a3..c9227469f523c930ab98b49567abf4dbd7213abe
If the notification level does not match, it returns nil. According to the specification, there are no restrictions on notifications when the level does not match, and the java-sdk and go-sdk implementations appear to be the same.
User-facing documentation should be included in the README.
@koic
User-facing documentation should be included in the README.
I wrote how to use notifications/message in the README.md, but I would like feedback on whether the text is easy to understand.
@dak2 FYI, the json_rpc_handler was merged into this ruby-sdk repository in #175.
@koic
Thanks for pointing that out!! I've made a few commits.